如何優(yōu)雅的快速搭建MVVM項(xiàng)目-MVVMFramework系列教程(三)

統(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

Github

MVVMFramework

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容