Android從零開始搭建MVVM架構(7) ———— 使用玩Android API帶你搭建MVVM框架(終極篇)

在上一篇咱們搭建了簡單的MVVM項目,並使用玩安卓API(感謝鴻洋),實現了一個簡單的banner的廣告功能。這篇,咱們要在上一篇的基礎上去優化java

從零開始搭建MVVM架構系列文章(持續更新):
Android從零開始搭建MVVM架構(1)————DataBinding
Android從零開始搭建MVVM架構(2)————ViewModel
Android從零開始搭建MVVM架構(3)————LiveData
Android從零開始搭建MVVM架構(4)————Room(從入門到進階)
Android從零開始搭建MVVM架構(5)————Lifecycles
Android從零開始搭建MVVM架構(6)————使用玩Android API帶你搭建MVVM框架(初級篇)
Android從零開始搭建MVVM架構(7) ———— 使用玩Android API帶你搭建MVVM框架(終極篇)android

1、拓展LiveData的功能。

在上篇,咱們發現只有接口請求成功了的操做。咱們正常項目中還會有,showloading、hideloading、聯網失敗,並且還有即便聯網成功也有可能沒有走通邏輯,如:關注失敗。等等,那麼一個LiveData只有一個onChange回調,怎麼?git

拓展LiveData<T>,泛型裏咱們是能夠隨便更改的,咱們新建一個Resource類,和咱們以前的ResponModel幾乎同樣,惟一有區別的是Resource類裏有不少狀態,來區分到底走的哪一個。github

public class Resource<T> {
    //狀態 這裏有多個狀態 0表示加載中;1表示成功;2表示聯網失敗;3表示接口雖然走通,但走的失敗(如:關注失敗)
    public static final int LOADING = 0;
    public static final int SUCCESS = 1;
    public static final int ERROR = 2;
    public static final int FAIL = 3;
    public static final int PROGRESS = 4;//注意只有下載文件和上傳圖片時纔會有
    public int state;

    public String errorMsg;
    public T data;
    public Throwable error;
    
     //這裏和文件和進度有關了
    public int precent;//文件下載百分比
    public long total;//文件總大小
    
    //這裏定義咱們狀態的回調
    public interface OnHandleCallback<T> {
        void onLoading(String showMessage);

        void onSuccess(T data);

        void onFailure(String msg);

        void onError(Throwable error);

        void onCompleted();

        void onProgress(int precent,long total);
    }
    
    //...省略部分代碼,便於理解
    
    //這裏是判斷,接口走通了,是否走了該走的邏輯,玩android api規則是code =0,算成功
    public static <T> Resource<T> response(ResponModel<T> data) {
        if (data != null) {
            if (data.isSuccess()) {
                return new Resource<>(SUCCESS, data.getData(), null);
            }
            return new Resource<>(FAIL, null, data.getErrorMsg());
        }
        return new Resource<>(ERROR, null, null);
    }


    public static <T> Resource<T> failure(String msg) {
        return new Resource<>(ERROR, null, msg);
    }

    public static <T> Resource<T> error(Throwable t) {
        return new Resource<>(ERROR, t);
    }

    public static <T> Resource<T> progress(int precent, long total) {
        return new Resource<>(PROGRESS, precent, total);
    }

    public void handler(OnHandleCallback<T> callback) {
        switch (state) {
            case LOADING:
                callback.onLoading(errorMsg);
                break;
            case SUCCESS:
                callback.onSuccess(data);
                break;
            case FAIL:
                callback.onFailure(errorMsg);
                break;
            case ERROR:
                callback.onError(error);
                break;
            case PROGRESS:
                callback.onProgress(precent,total);
                break;
        }

        if (state != LOADING) {
            callback.onCompleted();
        }
    }

    


}

複製代碼

加上這個Resource後,咱們再想一想,這些回調回來了。不可能每個去處理,因此咱們要想辦法把統一操做放在Base裏,並且還能隨意被重寫的。由於要showLoading,那就在BaseActivity裏來個抽象類,實現咱們Resource裏的接口回調。這裏爲何選擇抽象類,由於抽象類實現接口後,須要父類統一操做的能夠寫在方法體內,不須要操做的甚至能夠不操做,留給子類操做。若是子類不須要父類的統一操做,能夠主動重寫那個方法,而且把super()代碼去掉。編程

//這個是BaseActivity裏的內部類
public abstract class OnCallback<T> implements Resource.OnHandleCallback<T> {
        @Override
        public void onLoading(String msg) {
           //統一操做 showLoading
        }

        @Override
        public void onError(Throwable throwable) {
           //統一操做聯網失敗
        }

        @Override
        public void onFailure(String msg) {
           //接口走通了,可是code 不等於0
        }

        @Override
        public void onCompleted() {
            //統一關閉 hideLoading
        }

        @Override
        public void onProgress(int precent, long total) {
            //這是上傳圖片和下載文件才須要的。
        }
    }
複製代碼

這些作完以後,再來看看咱們如今的banner的網絡請求,api

public MutableLiveData<Resource<List<BannerBean>>> getBanners(){
        final MutableLiveData<Resource<List<BannerBean>>> liveData = new MutableLiveData<>();
        RetrofitManager.getInstance().getApiService().getBanner()
                .subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        //showLoading,後面傳參,是loading顯示文字配用
                        liveData.postValue(Resource.<List<BannerBean>>loading(""));
                    }
                })
                .subscribe(new Consumer<ResponModel<List<BannerBean>>>() {
                    @Override
                    public void accept(ResponModel<List<BannerBean>> listResponModel) throws Exception {
                        //成功
                        liveData.postValue(Resource.success(listResponModel.getData()));
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        //失敗
                        liveData.postValue(Resource.<List<BannerBean>>error(throwable));
                    }
                });

        return liveData;
    }
複製代碼

而在咱們的Activity裏,是這樣網絡

//由於我BaseActivity裏的OnCallback,沒有實現onSuccess方法,這裏會主動實現
//好比咱們BaseActivity裏的OnCallback裏,失敗的時候,Toast一句話,這個時候咱們不須要Toast,想要本身實現,那就重寫他,注意註釋super
mViewModel.getBanner().observe(this, new Observer<Resource<List<BannerBean>>>() {
            @Override
            public void onChanged(Resource<List<BannerBean>> listResource) {
                listResource.handler(new OnCallback<List<BannerBean>>() {
                    @Override
                    public void onSuccess(List<BannerBean> data) {
                        
                    }
                });
            }
        });
複製代碼

上面的代碼,看起來很複雜同樣,使用lambda表達式試試,變化以下(你會發現請求網絡和網絡回調,就用這幾句代碼搞定了,真的是很鏈式編程!!):架構

mViewModel.getBanner().observe(this, resource -> resource.handler(new OnCallback<List<BannerBean>>() {
            @Override
            public void onSuccess(List<BannerBean> data) {
                updateBanner(data);
            }
        }));
複製代碼

2、增長Model層

不少項目用Repository命名,數據倉庫層。Model層是個概念,想用什麼命名都行。爲何要添加這一層呢?先看上面ViewModel裏,聯網操做,不一樣的是Restrofit的接口 RetrofitApiService,其餘基本都一致的。那麼咱們要讓ViewModel成爲相似MVP中契約類的功能,人家只要看你的ViewModel,就知道有哪些邏輯和功能了。BaseModel以下(這裏RxJava + Retrofit的封裝用的我以前的一個封裝,這裏對這方面很少講的,本文在 此前作了些許改變,點擊這裏查看app

//BaseModel裏我封裝了不少,好比文件下載,上傳,這裏省略了部分代碼,便於理解
public abstract class BaseModel {
    //解決RxJava可能存在的內存泄漏
    public LifecycleTransformer objectLifecycleTransformer;
    //離開頁面,是否取消網絡
    public CompositeDisposable compositeDisposable;
    //若是開啓,同一url還在請求網絡時,不會
    public ArrayList<String> onNetTags;
    
    public RetrofitApiService getApiService() {
        return RetrofitManager.getRetrofitManager().getApiService();
    }
    
    //把統一操做所有放在這,ParamsBuilder是我定義的一個參數,需不須要Loading,loadingmessage,需不須要重連都在這裏。
    //不傳的話,都是默認值。封裝好後,子類只要傳Retrofit的網絡請求返回值,和LiveData返回值就Ok了
    public <T> MutableLiveData<T> observe(Observable observable, final MutableLiveData<T> liveData, ParamsBuilder paramsBuilder) {
        if (paramsBuilder == null) {
            paramsBuilder = paramsBuilder.build();
        }
        boolean showDialog = paramsBuilder.isShowDialog();
        String loadingMessage = paramsBuilder.getLoadingMessage();
        int onlineCacheTime = paramsBuilder.getOnlineCacheTime();
        int offlineCacheTime = paramsBuilder.getOfflineCacheTime();
        boolean cancleNet = paramsBuilder.isCancleNet();

        if (onlineCacheTime > 0) {
            setOnlineCacheTime(onlineCacheTime);
        }
        if (offlineCacheTime > 0) {
            setOfflineCacheTime(offlineCacheTime);
        }
        String oneTag = paramsBuilder.getOneTag();
        if (!TextUtils.isEmpty(oneTag)) {
            if (oneNetMap.contains(oneTag)) {
                return liveData;
            }
        }

        Disposable disposable = observable.subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        if (!TextUtils.isEmpty(oneTag)) {
                             onNetTags.add(oneTag);
                        }
                        if (showDialog) {
                            liveData.postValue((T) Resource.loading(loadingMessage));
                        }
                    }
                }).observeOn(AndroidSchedulers.mainThread())
                //防止RxJava內存泄漏
                .compose(objectLifecycleTransformer)
                .subscribe(new Consumer() {
                    @Override
                    public void accept(Object o) throws Exception {
                        liveData.postValue((T) Resource.response((ResponModel<Object>) o));
                        if (!TextUtils.isEmpty(oneTag)) {
                             onNetTags.remove(oneTag);
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        liveData.postValue((T) Resource.error(throwable));
                        if (!TextUtils.isEmpty(oneTag)) {
                             onNetTags.remove(oneTag);
                        }
                    }
                });


        if (cancleNet) {
            compositeDisposable.add(disposable);
        }
        return liveData;
    }
    
}
複製代碼

咱們在banner建一個Repository繼承BaseModel,以下:框架

public class HomeRepository extends BaseModel {
    //目前home裏只有一個請求banner列表的網絡請求
    public MutableLiveData<Resource<List<BannerBean>>> getBannerList() {
        MutableLiveData<Resource<List<BannerBean>>> liveData = new MutableLiveData<>();
        return observeGo(getApiService().getBanner(), liveData);
    }
}
複製代碼

這裏有一點要提下BaseModel裏的數據都是BaseViewModel裏傳過來的,由於ViewModel生命週期的緣由,因此如今的BaseViewModel是這樣的

public abstract class BaseViewModel<T extends BaseModel> extends AndroidViewModel {
    //這個是爲了退出頁面,取消請求的
    public CompositeDisposable compositeDisposable;
    private T repository;
    private ArrayList<String> onNetTags;

    protected abstract T createRepository();

    public BaseViewModel(@NonNull Application application) {
        super(application);
        this.repository = createRepository();
        compositeDisposable = new CompositeDisposable();
        onNetTags = new ArrayList<>();
    }

    public void setObjectLifecycleTransformer(LifecycleTransformer objectLifecycleTransformer) {
        //objectLifecycleTransformer是從BaseActivity傳過來的,RxFragmentActivity的生命週期
        repository.setObjectLifecycleTransformer(objectLifecycleTransformer);
        repository.setCompositeDisposable(compositeDisposable);
        repository.setOnNetTags(onNetTags);
    }

    public T getRepository() {
        return repository;
    }


    @Override
    protected void onCleared() {
        super.onCleared();
        //銷燬後,取消當前頁全部在執行的網絡請求。
        if (compositeDisposable != null) {
            compositeDisposable.dispose();
        }
    }
}
複製代碼

結束語

這是目前2個最大優化的點。項目還有不少優化的地方,包括已經優化的地方,這裏就不羅列了。我會利用空閒時間,把項目繼續更新下去。MVVM系列文章,就此結束了,很是感謝你的閱讀!

本文demo

相關文章
相關標籤/搜索