Android从零开始搭建MVVM架构(7) ———— 使用玩Android API带你搭建MVVM框架(终极篇)
在上一篇我们搭建了简单的MVVM项目,并使用玩安卓API(感谢鸿洋),实现了一个简单的banner的广告功能。这篇,我们要在上一篇的基础上去优化
从零开始搭建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框架(终极篇)
一、拓展LiveData的功能。
在上篇,我们发现只有接口请求成功了的操作。我们正常项目中还会有,showloading、hideloading、联网失败,而且还有即使联网成功也有可能没有走通逻辑,如:关注失败。等等,那么一个LiveData只有一个onChange回调,怎么?
拓展LiveData
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> {@Overridepublic void onLoading(String msg) {//统一操作 showLoading}@Overridepublic void onError(Throwable throwable) {//统一操作联网失败}@Overridepublic void onFailure(String msg) {//接口走通了,但是code 不等于0}@Overridepublic void onCompleted() {//统一关闭 hideLoading}@Overridepublic void onProgress(int precent, long total) {//这是上传图片和下载文件才需要的。}}
这些做完之后,再来看看我们现在的banner的网络请求,
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>() {@Overridepublic void accept(Disposable disposable) throws Exception {//showLoading,后面传参,是loading显示文字配用liveData.postValue(Resource.<BannerBean>>loading(""));}}).subscribe(new Consumer<ResponModel<List<BannerBean>>>() {@Overridepublic void accept(ResponModel<List<BannerBean>> listResponModel) throws Exception {//成功liveData.postValue(Resource.success(listResponModel.getData()));}}, new Consumer<Throwable>() {@Overridepublic void accept(Throwable throwable) throws Exception {//失败liveData.postValue(Resource.<BannerBean>>error(throwable));}});return liveData;}
而在我们的Activity里,是这样
//因为我BaseActivity里的OnCallback,没有实现onSuccess方法,这里会主动实现
//比如我们BaseActivity里的OnCallback里,失败的时候,Toast一句话,这个时候我们不需要Toast,想要自己实现,那就重写他,注意注释super
mViewModel.getBanner().observe(this, new Observer<Resource<List<BannerBean>>>() {@Overridepublic void onChanged(Resource<List<BannerBean>> listResource) {listResource.handler(new OnCallback<List<BannerBean>>() {@Overridepublic void onSuccess(List<BannerBean> data) {}});}});
上面的代码,看起来很复杂一样,使用lambda表达式试试,变化如下(你会发现请求网络和网络回调,就用这几句代码搞定了,真的是很链式编程!!):
mViewModel.getBanner().observe(this, resource -> resource.handler(new OnCallback<List<BannerBean>>() {@Overridepublic void onSuccess(List<BannerBean> data) {updateBanner(data);}}));
二、增加Model层
很多项目用Repository命名,数据仓库层。Model层是个概念,想用什么命名都行。为什么要添加这一层呢?先看上面ViewModel里,联网操作,不同的是Restrofit的接口 RetrofitApiService,其他基本都一致的。那么我们要让ViewModel成为类似MVP中契约类的功能,人家只要看你的ViewModel,就知道有哪些逻辑和功能了。BaseModel如下(这里RxJava + Retrofit的封装用的我之前的一个封装,这里对这方面不多讲的,本文在 此前做了些许改变,点击这里查看)
//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>() {@Overridepublic 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() {@Overridepublic void accept(Object o) throws Exception {liveData.postValue((T) Resource.response((ResponModel<Object>) o));if (!TextUtils.isEmpty(oneTag)) {onNetTags.remove(oneTag);}}}, new Consumer<Throwable>() {@Overridepublic 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;}@Overrideprotected void onCleared() {super.onCleared();//销毁后,取消当前页所有在执行的网络请求。if (compositeDisposable != null) {compositeDisposable.dispose();}}
}
结束语
这是目前2个最大优化的点。项目还有很多优化的地方,包括已经优化的地方,这里就不罗列了。我会利用空闲时间,把项目继续更新下去。MVVM系列文章,就此结束了。
本文demo
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!