[关闭]
@Tyhj 2018-11-26T09:29:22.000000Z 字数 7215 阅读 906

Android架构——MVP Clean

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

对mvp-clean的理解

todo-mvp-clean架构模式是基于标准MVP架构和Clean Architecture的概念相结合来设计实现的。

df56fc6b-69dc-45e2-ba01-50d585b31625.png-69.9kB

其实对比MVP架构,View层和Medle层是没有改变的,只是多了Domain Layer这层,是Presenter层和Data层之间通信的桥梁,并且对数据进行了业务处理;这一层是通过一个个Use Case组成的,代表每一个业务逻辑,更方便代码的复用和维护;数据操作的细节由Data层实现;从而进一步将Presenter层和Data层解耦。

对比MVP架构,我能理解的就是把P层的业务逻辑转移到了Domain Layer中,而且每一个业务逻辑都可以新建一个Use Case,细化了业务,而且提高了代码的重用性;

具体实现

Google的demo看着打一遍差不多就能理解意思了,但是项目用了Dagger注入框架和其他测试框架,看起来可能比较麻烦,就自己写了一个简单的,便于理解;栗子还是和上篇MVP框架一样,只是新增了一个Domain Layer层,所以只展示其创建过程和其他改变;功能:

屏幕快照 2018-11-26 上午9.54.37.png

可以看出新增了几个类,首先是UseCaseUseCaseHandler,就是对业务逻辑的一个抽象和管理;UseCase抽象出请求参数、返回参数、数据返回回调接口

  1. public abstract class UseCase<Q extends UseCase.RequestValues, P extends UseCase.ResponseValue> {
  2. //请求参数
  3. private Q mRequestValues;
  4. //返回监听
  5. private UseCaseCallback<P> mUseCaseCallback;
  6. //执行业务
  7. void run() {
  8. executeUseCase(mRequestValues);
  9. }
  10. //执行的具体方法
  11. protected abstract void executeUseCase(Q requestValues);
  12. /**
  13. * 请求参数
  14. */
  15. public interface RequestValues {
  16. }
  17. /**
  18. * 返回参数
  19. */
  20. public interface ResponseValue {
  21. }
  22. //返回回调
  23. public interface UseCaseCallback<R> {
  24. void onSuccess(R response);
  25. void onError();
  26. }
  27. }

UseCaseHandler是对UseCase进行管理,使用到UseCaseSchedulerUseCaseThreadPoolScheduler这两个类来进行线程的调度,UseCaseScheduler抽象出方法,UseCaseThreadPoolScheduler实现方法,在线程池中执行异步任务;任务的结果回调用Handler post的方式来切换到主线程

UseCaseHandler进行分析,其实就两个部分:执行任务、返回结果,还有使用了线程调度来管理整个过程

处理结果

在主线程中处理结果和异常方法

  1. /**
  2. * 返回数据
  3. *
  4. * @param response
  5. * @param useCaseCallback
  6. * @param <V>
  7. */
  8. public <V extends UseCase.ResponseValue> void notifyResponse(final V response,
  9. final UseCase.UseCaseCallback<V> useCaseCallback) {
  10. mUseCaseScheduler.notifyResponse(response, useCaseCallback);
  11. }
  12. /**
  13. * 返回错误
  14. *
  15. * @param useCaseCallback
  16. * @param <V>
  17. */
  18. private <V extends UseCase.ResponseValue> void notifyError(final UseCase.UseCaseCallback<V> useCaseCallback) {
  19. mUseCaseScheduler.onError(useCaseCallback);
  20. }

执行业务方法

传入请求参数和回调参数,并给UseCase设置回调UiCallbackWrapper,然后在线程池中执行具体的业务方法

  1. public <T extends UseCase.RequestValues, R extends UseCase.ResponseValue> void execute(
  2. final UseCase<T, R> useCase, T values, UseCase.UseCaseCallback<R> callback) {
  3. useCase.setRequestValues(values);
  4. useCase.setUseCaseCallback(new UiCallbackWrapper(callback, this));
  5. mUseCaseScheduler.execute(new Runnable() {
  6. @Override
  7. public void run() {
  8. useCase.run();
  9. }
  10. });
  11. }

UiCallbackWrapper

继承UseCase.UseCaseCallback,目的是执行完业务后,UseCase执行回调就会调用UseCaseHandler的两个在主线程中处理结果的方法

  1. private static final class UiCallbackWrapper<V extends UseCase.ResponseValue> implements UseCase.UseCaseCallback<V> {
  2. private final UseCase.UseCaseCallback<V> mCallback;
  3. private final UseCaseHandler mUseCaseHandler;
  4. public UiCallbackWrapper(UseCase.UseCaseCallback<V> callback, UseCaseHandler useCaseHandler) {
  5. mCallback = callback;
  6. mUseCaseHandler = useCaseHandler;
  7. }
  8. @Override
  9. public void onSuccess(V response) {
  10. mUseCaseHandler.notifyResponse(response, mCallback);
  11. }
  12. @Override
  13. public void onError() {
  14. mUseCaseHandler.notifyError(mCallback);
  15. }
  16. }

主要的东西就在这个类里面,其实就是使用了命令模式,对UseCase进行了统一的管理,维护了一个UseCaseThreadPoolScheduler 对象来执行异步任务并在UI线程返回结果

具体使用

创建UseCase

每个业务就应该新建一个UseCase,按照Clean的原则,UseCase是业务逻辑层,是由纯Java来实现的,不应该有Android库的依赖;保存图片地址到数据库为例,新建一个AddPicture用例继承UseCase

  1. public class AddPicture extends UseCase<AddPicture.RequestValues, AddPicture.ResponseValue>
实现请求参数接口

用一个内部类实现请求参数接口,保存图片,图片是一个File对象

  1. public static final class RequestValues implements UseCase.RequestValues {
  2. File pictureFile;
  3. public RequestValues(File pictureFile) {
  4. this.pictureFile = pictureFile;
  5. }
  6. public File getPictureFile() {
  7. return pictureFile;
  8. }
  9. }
实现返回参数接口

返回数据是一个定义的Picture对象,用于更新界面;

  1. public static final class ResponseValue implements UseCase.ResponseValue {
  2. Picture mPicture;
  3. public ResponseValue(Picture picture) {
  4. mPicture = picture;
  5. }
  6. public Picture getPicture() {
  7. return mPicture;
  8. }
  9. }
实现执行方法

执行方法其实就是在数据库中插入一条数据

  1. @Override
  2. protected void executeUseCase(RequestValues requestValues) {
  3. Picture picture = new Picture(requestValues.getPictureFile());
  4. mLocalDataSource.savePic(picture);
  5. getUseCaseCallback().onSuccess(new ResponseValue(picture));
  6. }

在Persenter中实现数据获取

P层直接调用mUseCaseHandler执行业务方法,获取到数据给View更新界面

  1. @Override
  2. public void addPic(File file) {
  3. AddPicture.RequestValues requestValues=new AddPicture.RequestValues(file);
  4. mUseCaseHandler.execute(mAddPicture, requestValues, new UseCase.UseCaseCallback<AddPicture.ResponseValue>() {
  5. @Override
  6. public void onSuccess(AddPicture.ResponseValue response) {
  7. mPicturesActivity.addPic(response.getPicture());
  8. }
  9. @Override
  10. public void onError() {
  11. }
  12. });
  13. }

以选择图片,保存到数据库这个功能来看,调用系统相册选择图片这一步属于数据的获取,但更是界面操作,之前MVP,我封装了图片选择工具,把图片选择写在了P层,现在P层不写业务逻辑,UseCase是纯Java的业务逻辑,所以其实应该是写在View层;

执行过程分析

首先在View层选择图片以后,调动Persenter方法

  1. PicturePickUtil.pick(PicturesActivity.this, new OnPickListener() {
  2. @Override
  3. public void pickPicture(File file) {
  4. mPresenter.addPic(file);
  5. }
  6. });

在Presenter里面,根据File构建出请求参数,创建AddPicture对象,执行mUseCaseHandler.execute()方法;

  1. //创建用例
  2. mAddPicture=new AddPicture(mLocalDataSource);
  3. @Override
  4. public void addPic(File file) {
  5. AddPicture.RequestValues requestValues=new AddPicture.RequestValues(file);
  6. mUseCaseHandler.execute(mAddPicture, requestValues, new UseCase.UseCaseCallback<AddPicture.ResponseValue>() {
  7. @Override
  8. public void onSuccess(AddPicture.ResponseValue response) {
  9. mPicturesActivity.addPic(response.getPicture());
  10. }
  11. @Override
  12. public void onError() {
  13. }
  14. });
  15. }

mUseCaseHandler.execute()的方法就是给mAddPicture设置了请求参数和返回回调,并异步执行mAddPicture.run()方法

  1. public <T extends UseCase.RequestValues, R extends UseCase.ResponseValue> void execute(
  2. final UseCase<T, R> useCase, T values, UseCase.UseCaseCallback<R> callback) {
  3. useCase.setRequestValues(values);
  4. useCase.setUseCaseCallback(new UiCallbackWrapper(callback, this));
  5. mUseCaseScheduler.execute(new Runnable() {
  6. @Override
  7. public void run() {
  8. useCase.run();
  9. }
  10. });
  11. }

mAddPicture.run()方法执行了mAddPicture.executeUseCase()方法,也就是保存数据,并且生成返回数据执行getUseCaseCallback().onSuccess()回调方法;

  1. @Override
  2. protected void executeUseCase(RequestValues requestValues) {
  3. Picture picture = new Picture(requestValues.getPictureFile());
  4. mLocalDataSource.savePic(picture);
  5. getUseCaseCallback().onSuccess(new ResponseValue(picture));
  6. }

getUseCaseCallback().onSuccess()回调方法就是UseCaseHandler中的内部类UiCallbackWrapper中的方法

  1. @Override
  2. public void onSuccess(V response) {
  3. mUseCaseHandler.notifyResponse(response, mCallback);
  4. }

也就是执行了mUseCaseHandler.notifyResponse(response, mCallback)方法

  1. public <V extends UseCase.ResponseValue> void notifyResponse(final V response,
  2. final UseCase.UseCaseCallback<V> useCaseCallback) {
  3. mUseCaseScheduler.notifyResponse(response, useCaseCallback);
  4. }

也就是执行了mUseCaseScheduler.notifyResponse方法

  1. @Override
  2. public <V extends UseCase.ResponseValue> void notifyResponse(final V response, final UseCase.UseCaseCallback<V> useCaseCallback) {
  3. mHandler.post(new Runnable() {
  4. @Override
  5. public void run() {
  6. useCaseCallback.onSuccess(response);
  7. }
  8. });
  9. }

到了这里,就是在主线程中执行了返回数据的方法,就是在Presenter里面new的这个UseCaseCallback返回了数据

  1. mUseCaseHandler.execute(mGetPictures, new GetPictures.RequestValues(), new UseCase.UseCaseCallback<GetPictures.ResponseValue>() {
  2. @Override
  3. public void onSuccess(GetPictures.ResponseValue response) {
  4. mPicturesActivity.showPic(response.getPictures());
  5. }
  6. @Override
  7. public void onError() {
  8. }
  9. });

最后交给mPicturesActivity进行更新界面,整个流程完成

  1. //添加图片
  2. @Override
  3. public void addPic(Picture picture) {
  4. mPictureAdapter.insertData(0, picture);
  5. }

个人感觉这个架构还是很有用的,做业务逻辑比较多的APP还是很适合的,反正就是低耦合,每个业务都是独立的,复用性很高;如果配合上dagger依赖注入框架就更能感受到低耦合了;缺点就是每个小的逻辑都可以创建一个UseCase会创建更多的类

项目地址:https://github.com/tyhjh/AndroidMvp

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注