统一规范的BaseViewModel和HttpServiceCallBack已经建好,那么把两者关联起来实现加载列表内容的时刻到了。
列表特性就是分页去加载数据,默认的按 page(当前第几页) 和 pageSize(一页多少个item)来控制分页,而当加载数据返回的item 数量比 pageSize 小则视为没有更多数据了,所以列表拓展BaseViewModel多一个hasMore的状态判断是否有下一页数据。
因为列表有个下拉刷新的概念,加载第一页的时候认为是刷新中状态。
然后我们在BaseListViewModel中实现上面提到的逻辑,并且实现HttpServiceCallBack来设置对应状态。
public HttpServiceCallBack callBack = new HttpServiceCallBack>() {
@Override
public void onHttpSuccess(List resultData, String msg) {
setStatusError(false);
setStatusNetworkError(false);
if(isFirstPage()) {
items.clear();
}
if(resultData != null) {
items.addAll(items.size() - footers.size(),resultData);
//如果获取的数据数量比申请的数量少 则为没有更多了
hasMore.set(resultData.size() < pageSize ? false : true);
}
}
@Override
public void onHttpFail(int code, String msg) {
setStatusError(true);
}
@Override
public void onNetWorkError() {
setStatusNetworkError(true);
}
@Override
public void onHttpComplete() {
once = true;
setStatusLoading(false);
if(!getStatusError().get()&&!getStatusNetworkError().get())
setStatusEmpty(items.isEmpty());
if(isFirstPage())//因为在刷新之前已经把page设为了firstPage,所以可以判断isFirstPage()来判断当前是否刷新
setRefreshing(false);
else
loadingMore.set(false);
onLoadListComplete();
}
};
callBack中已经进行了各种状态的设置,根据Databinding特性,只要在xml中绑定了对应属性即可显示隐藏对应View。
然后通过提供一个onLoadListHttpRequest抽象函数,只要继承BaseListViewModel的子类实现onLoadListHttpRequest函数即可轻松关联请求的接口。而onLoadListComplete提供出来
然后继续拓展Header和Footer,具体请看源码。
items通过Databinding绑定layout,从构造函数中传入layout 的id,通过ItemViewSelector来进行绑定,具体原理请参考binding-collection-adapter
因为现在都用RecyclerView了,ListView控件我早已弃用,基于BaseListViewModel 再拓展 RecyclerView专属的BaseRecyclerViewModel,主要实现setItemDecoration,setLayoutManager,onItemClickListener,onScrollListener。然后在BindingConfig里面编写转换器:
@BindingAdapter({"addOnItemClick"})
public static void addOnItemClick(RecyclerView view, RecyclerViewItemClickSupport.OnItemClickListener listener) {
RecyclerViewItemClickSupport.addTo(view).setOnItemClickListener(listener);
}
@BindingAdapter({"addOnScrollListener"})
public static void addOnScrollListener(RecyclerView view, RecyclerView.OnScrollListener listener) {
if(listener!=null)
view.setOnScrollListener(listener);
}
@BindingAdapter({"addItemDecoration"})
public static void addItemDecoration(RecyclerView view, RecyclerView.ItemDecoration itemDecoration) {
if(itemDecoration != null)
view.addItemDecoration(itemDecoration);
}
那么对应在xml中加入属性:
app:addOnItemClick="@{viewModel.onItemClickListener}"
app:addOnScrollListener="@{viewModel.onScrollListener}"
app:addItemDecoration="@{viewModel.itemDecoration}"
这样就完成绑定。那么我们把这个xml写成通用的,并加入layout_behavior兼容CoordinatorLayout进行toolbar等联动效果,把这些变为一个include文件即可。完整的xml如下(include_recyclerview.xml):
如此,通用的RecyclerViewModel完成。使用起来就相当方便了。
新建一个ViewModel extends BaseRecyclerViewModel,重写onLoadListHttpRequest,onItemClick函数,在构造函数中把列表的 item layout xml通过super传给父类。然后在xml 中 include 上面的 include_recyclerview.xml:
一切就是这么简单,ViewModel 里面 只要传入item layout,告诉ViewModel请求什么地址,点击做什么操作,onListRefresh之后一个列表就呈现在你眼前。
玩出花样
ViewModel里面设置
- setItemDecoration 设置RecyclerView的ItemDecoration。
- setLayoutManager 设置RecyclerView的样式,linear,grid,staggeredGrid。
- setSpecialView 设置RecyclerView的item 特别样式
- addHeader 设置RecyclerView的 headerView
- addFooter 设置RecyclerView的 footerView
Github
MVVMFramework