@Tyhj
2018-11-26T09:29:22.000000Z
字数 7215
阅读 1645
Android
todo‑mvp‑clean是Google的Android Architecture Blueprints(Android架构蓝图)中的一个用MVP架构和Clean架构来构架APP的demo,这篇文章主要是看完官方demo以后,谈谈对Android中使用MVP+Clean的理解
浅谈Android架构——MVP:https://www.jianshu.com/p/9050e3dbe513
todo-mvp-clean架构模式是基于标准MVP架构和Clean Architecture的概念相结合来设计实现的。

其实对比MVP架构,View层和Medle层是没有改变的,只是多了Domain Layer这层,是Presenter层和Data层之间通信的桥梁,并且对数据进行了业务处理;这一层是通过一个个Use Case组成的,代表每一个业务逻辑,更方便代码的复用和维护;数据操作的细节由Data层实现;从而进一步将Presenter层和Data层解耦。
对比MVP架构,我能理解的就是把P层的业务逻辑转移到了Domain Layer中,而且每一个业务逻辑都可以新建一个Use Case,细化了业务,而且提高了代码的重用性;
Google的demo看着打一遍差不多就能理解意思了,但是项目用了Dagger注入框架和其他测试框架,看起来可能比较麻烦,就自己写了一个简单的,便于理解;栗子还是和上篇MVP框架一样,只是新增了一个Domain Layer层,所以只展示其创建过程和其他改变;功能:

可以看出新增了几个类,首先是UseCase和UseCaseHandler,就是对业务逻辑的一个抽象和管理;UseCase抽象出请求参数、返回参数、数据返回回调接口
public abstract class UseCase<Q extends UseCase.RequestValues, P extends UseCase.ResponseValue> {//请求参数private Q mRequestValues;//返回监听private UseCaseCallback<P> mUseCaseCallback;//执行业务void run() {executeUseCase(mRequestValues);}//执行的具体方法protected abstract void executeUseCase(Q requestValues);/*** 请求参数*/public interface RequestValues {}/*** 返回参数*/public interface ResponseValue {}//返回回调public interface UseCaseCallback<R> {void onSuccess(R response);void onError();}}
UseCaseHandler是对UseCase进行管理,使用到UseCaseScheduler和UseCaseThreadPoolScheduler这两个类来进行线程的调度,UseCaseScheduler抽象出方法,UseCaseThreadPoolScheduler实现方法,在线程池中执行异步任务;任务的结果回调用Handler post的方式来切换到主线程
对UseCaseHandler进行分析,其实就两个部分:执行任务、返回结果,还有使用了线程调度来管理整个过程
在主线程中处理结果和异常方法
/*** 返回数据** @param response* @param useCaseCallback* @param <V>*/public <V extends UseCase.ResponseValue> void notifyResponse(final V response,final UseCase.UseCaseCallback<V> useCaseCallback) {mUseCaseScheduler.notifyResponse(response, useCaseCallback);}/*** 返回错误** @param useCaseCallback* @param <V>*/private <V extends UseCase.ResponseValue> void notifyError(final UseCase.UseCaseCallback<V> useCaseCallback) {mUseCaseScheduler.onError(useCaseCallback);}
传入请求参数和回调参数,并给UseCase设置回调UiCallbackWrapper,然后在线程池中执行具体的业务方法
public <T extends UseCase.RequestValues, R extends UseCase.ResponseValue> void execute(final UseCase<T, R> useCase, T values, UseCase.UseCaseCallback<R> callback) {useCase.setRequestValues(values);useCase.setUseCaseCallback(new UiCallbackWrapper(callback, this));mUseCaseScheduler.execute(new Runnable() {@Overridepublic void run() {useCase.run();}});}
继承UseCase.UseCaseCallback,目的是执行完业务后,UseCase执行回调就会调用UseCaseHandler的两个在主线程中处理结果的方法
private static final class UiCallbackWrapper<V extends UseCase.ResponseValue> implements UseCase.UseCaseCallback<V> {private final UseCase.UseCaseCallback<V> mCallback;private final UseCaseHandler mUseCaseHandler;public UiCallbackWrapper(UseCase.UseCaseCallback<V> callback, UseCaseHandler useCaseHandler) {mCallback = callback;mUseCaseHandler = useCaseHandler;}@Overridepublic void onSuccess(V response) {mUseCaseHandler.notifyResponse(response, mCallback);}@Overridepublic void onError() {mUseCaseHandler.notifyError(mCallback);}}
主要的东西就在这个类里面,其实就是使用了命令模式,对UseCase进行了统一的管理,维护了一个UseCaseThreadPoolScheduler 对象来执行异步任务并在UI线程返回结果
每个业务就应该新建一个UseCase,按照Clean的原则,UseCase是业务逻辑层,是由纯Java来实现的,不应该有Android库的依赖;保存图片地址到数据库为例,新建一个AddPicture用例继承UseCase
public class AddPicture extends UseCase<AddPicture.RequestValues, AddPicture.ResponseValue>
用一个内部类实现请求参数接口,保存图片,图片是一个File对象
public static final class RequestValues implements UseCase.RequestValues {File pictureFile;public RequestValues(File pictureFile) {this.pictureFile = pictureFile;}public File getPictureFile() {return pictureFile;}}
返回数据是一个定义的Picture对象,用于更新界面;
public static final class ResponseValue implements UseCase.ResponseValue {Picture mPicture;public ResponseValue(Picture picture) {mPicture = picture;}public Picture getPicture() {return mPicture;}}
执行方法其实就是在数据库中插入一条数据
@Overrideprotected void executeUseCase(RequestValues requestValues) {Picture picture = new Picture(requestValues.getPictureFile());mLocalDataSource.savePic(picture);getUseCaseCallback().onSuccess(new ResponseValue(picture));}
P层直接调用mUseCaseHandler执行业务方法,获取到数据给View更新界面
@Overridepublic void addPic(File file) {AddPicture.RequestValues requestValues=new AddPicture.RequestValues(file);mUseCaseHandler.execute(mAddPicture, requestValues, new UseCase.UseCaseCallback<AddPicture.ResponseValue>() {@Overridepublic void onSuccess(AddPicture.ResponseValue response) {mPicturesActivity.addPic(response.getPicture());}@Overridepublic void onError() {}});}
以选择图片,保存到数据库这个功能来看,调用系统相册选择图片这一步属于数据的获取,但更是界面操作,之前MVP,我封装了图片选择工具,把图片选择写在了P层,现在P层不写业务逻辑,UseCase是纯Java的业务逻辑,所以其实应该是写在View层;
首先在View层选择图片以后,调动Persenter方法
PicturePickUtil.pick(PicturesActivity.this, new OnPickListener() {@Overridepublic void pickPicture(File file) {mPresenter.addPic(file);}});
在Presenter里面,根据File构建出请求参数,创建AddPicture对象,执行mUseCaseHandler.execute()方法;
//创建用例mAddPicture=new AddPicture(mLocalDataSource);@Overridepublic void addPic(File file) {AddPicture.RequestValues requestValues=new AddPicture.RequestValues(file);mUseCaseHandler.execute(mAddPicture, requestValues, new UseCase.UseCaseCallback<AddPicture.ResponseValue>() {@Overridepublic void onSuccess(AddPicture.ResponseValue response) {mPicturesActivity.addPic(response.getPicture());}@Overridepublic void onError() {}});}
mUseCaseHandler.execute()的方法就是给mAddPicture设置了请求参数和返回回调,并异步执行mAddPicture.run()方法
public <T extends UseCase.RequestValues, R extends UseCase.ResponseValue> void execute(final UseCase<T, R> useCase, T values, UseCase.UseCaseCallback<R> callback) {useCase.setRequestValues(values);useCase.setUseCaseCallback(new UiCallbackWrapper(callback, this));mUseCaseScheduler.execute(new Runnable() {@Overridepublic void run() {useCase.run();}});}
mAddPicture.run()方法执行了mAddPicture.executeUseCase()方法,也就是保存数据,并且生成返回数据执行getUseCaseCallback().onSuccess()回调方法;
@Overrideprotected void executeUseCase(RequestValues requestValues) {Picture picture = new Picture(requestValues.getPictureFile());mLocalDataSource.savePic(picture);getUseCaseCallback().onSuccess(new ResponseValue(picture));}
getUseCaseCallback().onSuccess()回调方法就是UseCaseHandler中的内部类UiCallbackWrapper中的方法
@Overridepublic void onSuccess(V response) {mUseCaseHandler.notifyResponse(response, mCallback);}
也就是执行了mUseCaseHandler.notifyResponse(response, mCallback)方法
public <V extends UseCase.ResponseValue> void notifyResponse(final V response,final UseCase.UseCaseCallback<V> useCaseCallback) {mUseCaseScheduler.notifyResponse(response, useCaseCallback);}
也就是执行了mUseCaseScheduler.notifyResponse方法
@Overridepublic <V extends UseCase.ResponseValue> void notifyResponse(final V response, final UseCase.UseCaseCallback<V> useCaseCallback) {mHandler.post(new Runnable() {@Overridepublic void run() {useCaseCallback.onSuccess(response);}});}
到了这里,就是在主线程中执行了返回数据的方法,就是在Presenter里面new的这个UseCaseCallback返回了数据
mUseCaseHandler.execute(mGetPictures, new GetPictures.RequestValues(), new UseCase.UseCaseCallback<GetPictures.ResponseValue>() {@Overridepublic void onSuccess(GetPictures.ResponseValue response) {mPicturesActivity.showPic(response.getPictures());}@Overridepublic void onError() {}});
最后交给mPicturesActivity进行更新界面,整个流程完成
//添加图片@Overridepublic void addPic(Picture picture) {mPictureAdapter.insertData(0, picture);}
个人感觉这个架构还是很有用的,做业务逻辑比较多的APP还是很适合的,反正就是低耦合,每个业务都是独立的,复用性很高;如果配合上dagger依赖注入框架就更能感受到低耦合了;缺点就是每个小的逻辑都可以创建一个UseCase会创建更多的类