統(tǒng)一規(guī)范的BaseViewModel和HttpServiceCallBack已經(jīng)建好,那么把兩者關(guān)聯(lián)起來(lái)實(shí)現(xiàn)加載列表內(nèi)容的時(shí)刻到了。
列表特性就是分頁(yè)去加載數(shù)據(jù),默認(rèn)的按 page(當(dāng)前第幾頁(yè)) 和 pageSize(一頁(yè)多少個(gè)item)來(lái)控制分頁(yè),而當(dāng)加載數(shù)據(jù)返回的item 數(shù)量比 pageSize 小則視為沒有更多數(shù)據(jù)了,所以列表拓展BaseViewModel多一個(gè)hasMore的狀態(tài)判斷是否有下一頁(yè)數(shù)據(jù)。
因?yàn)榱斜碛袀€(gè)下拉刷新的概念,加載第一頁(yè)的時(shí)候認(rèn)為是刷新中狀態(tài)。
然后我們?cè)贐aseListViewModel中實(shí)現(xiàn)上面提到的邏輯,并且實(shí)現(xiàn)HttpServiceCallBack來(lái)設(shè)置對(duì)應(yīng)狀態(tài)。
public HttpServiceCallBack callBack = new HttpServiceCallBack<List<T>>() {
@Override
public void onHttpSuccess(List<T> resultData, String msg) {
setStatusError(false);
setStatusNetworkError(false);
if(isFirstPage()) {
items.clear();
}
if(resultData != null) {
items.addAll(items.size() - footers.size(),resultData);
//如果獲取的數(shù)據(jù)數(shù)量比申請(qǐng)的數(shù)量少 則為沒有更多了
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())//因?yàn)樵谒⑿轮耙呀?jīng)把page設(shè)為了firstPage,所以可以判斷isFirstPage()來(lái)判斷當(dāng)前是否刷新
setRefreshing(false);
else
loadingMore.set(false);
onLoadListComplete();
}
};
callBack中已經(jīng)進(jìn)行了各種狀態(tài)的設(shè)置,根據(jù)Databinding特性,只要在xml中綁定了對(duì)應(yīng)屬性即可顯示隱藏對(duì)應(yīng)View。
然后通過(guò)提供一個(gè)onLoadListHttpRequest抽象函數(shù),只要繼承BaseListViewModel的子類實(shí)現(xiàn)onLoadListHttpRequest函數(shù)即可輕松關(guān)聯(lián)請(qǐng)求的接口。而onLoadListComplete提供出來(lái)
然后繼續(xù)拓展Header和Footer,具體請(qǐng)看源碼。
items通過(guò)Databinding綁定layout,從構(gòu)造函數(shù)中傳入layout 的id,通過(guò)ItemViewSelector來(lái)進(jìn)行綁定,具體原理請(qǐng)參考binding-collection-adapter
因?yàn)楝F(xiàn)在都用RecyclerView了,ListView控件我早已棄用,基于BaseListViewModel 再拓展 RecyclerView專屬的BaseRecyclerViewModel,主要實(shí)現(xiàn)setItemDecoration,setLayoutManager,onItemClickListener,onScrollListener。然后在BindingConfig里面編寫轉(zhuǎn)換器:
@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);
}
那么對(duì)應(yīng)在xml中加入屬性:
app:addOnItemClick="@{viewModel.onItemClickListener}"
app:addOnScrollListener="@{viewModel.onScrollListener}"
app:addItemDecoration="@{viewModel.itemDecoration}"
這樣就完成綁定。那么我們把這個(gè)xml寫成通用的,并加入layout_behavior兼容CoordinatorLayout進(jìn)行toolbar等聯(lián)動(dòng)效果,把這些變?yōu)橐粋€(gè)include文件即可。完整的xml如下(include_recyclerview.xml):
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.bigkoo.mvvmframework.viewmodel.BaseRecyclerViewModel" />
<variable
name="adapterClassName"
type="String" />
<import type="me.tatarka.bindingcollectionadapter.LayoutManagers" />
</data>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
app:adapter='@{adapterClassName??"me.tatarka.bindingcollectionadapter.BindingRecyclerViewAdapter"}'
app:addOnItemClick="@{viewModel.onItemClickListener}"
app:addOnScrollListener="@{viewModel.onScrollListener}"
app:itemView="@{viewModel.itemViews}"
app:addItemDecoration="@{viewModel.itemDecoration}"
app:items="@{viewModel.items}"
app:layoutManager="@{viewModel.layoutManager}"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</layout>
如此,通用的RecyclerViewModel完成。使用起來(lái)就相當(dāng)方便了。
新建一個(gè)ViewModel extends BaseRecyclerViewModel,重寫onLoadListHttpRequest,onItemClick函數(shù),在構(gòu)造函數(shù)中把列表的 item layout xml通過(guò)super傳給父類。然后在xml 中 include 上面的 include_recyclerview.xml:
<include layout="@layout/include_recyclerview_refresh"
app:viewModel="@{viewModel}"/>
一切就是這么簡(jiǎn)單,ViewModel 里面 只要傳入item layout,告訴ViewModel請(qǐng)求什么地址,點(diǎn)擊做什么操作,onListRefresh之后一個(gè)列表就呈現(xiàn)在你眼前。
玩出花樣
ViewModel里面設(shè)置
- setItemDecoration 設(shè)置RecyclerView的ItemDecoration。
- setLayoutManager 設(shè)置RecyclerView的樣式,linear,grid,staggeredGrid。
- setSpecialView 設(shè)置RecyclerView的item 特別樣式
- addHeader 設(shè)置RecyclerView的 headerView
- addFooter 設(shè)置RecyclerView的 footerView