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

相关文章
相关标签/搜索