Google MVP 你也可以运用自如

作者: 無名小子的杂货铺 | 来源:发表于2016-08-25 15:50 被阅读572次

    MVP 思想已经盛行有一段时间了,之前写过几个简单的 MVP Demo,来分离 UI 和逻辑,前段时间研究了 googlesamples/android-architecture,这个库包含了好几种 MVP 例子,我针对 todo-mvp todo-mvp-clean 这两个例子进行了研究,其他几个例子有不同的侧重,但最基本的还是 todo-mvp ,其他只是在这个基础之上做扩充而已,还有一些用到了 Rxjava 的东西,由于项目中没有使用,也就没有详细研究,下面来说说这两个库最基本的用法。

    概况

    首先要认识到 MVP 是一个思想不是一个框架,不是任何东西都要用它来实现,针对特别简单或者特别复杂的需求或者页面,应根据实际情况来选择,而且要选择使用哪个 MVP 模式作为基本思想。

    todo-mvp

    Basic Model-View-Presenter architecture,这个是最基本的 MVP 思想,规定了最基本的 View 和 Presenter,使用者需要继承这两个类,来根据实际情况,增加自己的接口关系,这里的 View 和 Presenter 都在一个类中维护 Contract,在官方 Demo 中,Model 数据层的 Repository 在创建 Presenter 的时候就传进来的,而且还是使用的接口,这样也增加了可扩展性,缺点是在调用 M 是一层一层的传递,略显麻烦,不过从代码结构上是清晰的。

    这里引用一张官方的图解:

    todo-mvp.png

    todo-mvp-clean

    Based on todo-mvp, uses concepts from Clean Architecture,依靠的还是还是基本的 MVP todo-mvp,只不过在 Model 层做了优化,引入了 Domain Layer 层, Presenter 将不直接调用数据层,而是使用 usecase 方式。

    Presenter 要和 Model 打交道,必须通过 Domain 这一层,UseCase 中提供了最基本的请求和回调参数,以及如何调用的抽象方法,每一个子类继承 UseCase 来实现自己的 UseCase,同时又有一个 UseCaseHandler 工具类来管理这些 UseCase 的执行和回调,UseCase 和 UseCaseHandler 都是提供的基类,可以重复利用,对于 case 比较多的案例还是比较适用的。还有这里面有一些线程池的使用,实现类 UseCaseThreadPoolScheduler,来自定义我们的线程调度,包括使用什么队列,线程池大小等。经实际操作验证,一般的页面无需使用这么复杂的结构,如果针对请求情况比较多的 case,可以使用这个。

    Model 这一层在 UseCase 中实现,并且和 todo-mvp 一致,数据层的 Repository 在创建 Presenter 时候也要传入到 UseCase 中。

    这里引用一张官方的图解:

    todo-mvp-clean.png

    todo-mvp 和 todo-mvp-clean 对比

    我们从两张图就能很清晰的看出来 todo-mvp-clean 相对 todo-mvp 新增了 Domain 这一层,使用了 UseCase 方式,将 M 数据层的操作又进一步封装,放入 UseCase 中执行,其他的 V、P 层没有大的变化。

    利:

    • 代码结构清晰,将每个 case 分离互不干扰,而且请求、回调等进行统一化管理,不在过多的依靠外部提供的接口,增加了灵活性;
    • 将 view 和逻辑分离,在整合基线明星页过程中,并没有对view层关注,完全屏蔽掉,直进行 Presenter 分发处理,大大增加了效率;
    • Usecase 中有关于线程池的控制以及主线程回调操作;

    弊:

    • 新增 Usecase 导致代码增多,因为分离的非常细,首先回增加 Usecase 部分的核心代码(这部分可以共用),其次增加了每个具体的 Usecase 类,使得代码整体结构会增加;
    • 简单页面不太适合使用 Usecase,建议使用 Base MVP 即可;

    其他

    • 注意 final 的使用:

      private final Contract.View mView;
      private final UseCaseHandler mUseCaseHandler;
      private final GetCase1 mGetCase1;
      
      public AcitivtyPresenter(UseCaseHandler useCaseHandler, Contract.View statisticsView, GetCase1 getStatistics) {
        mUseCaseHandler = ActivityUtils.checkNotNull(useCaseHandler, "useCaseHandler cannot be null!");
        mView = ActivityUtils.checkNotNull(statisticsView, "StatisticsView cannot be null!");
        mGetCase1 = ActivityUtils.checkNotNull(getStatistics, "getStatistics cannot be null!");
        mView.setPresenter(this);
      

    也建议规范使用 final ,可以避免自己无意重新赋值或者不创建。

    • 关于参数的封装:

        public static class RequestValues implements UseCase.RequestValues {
      
        }  
      
        public static class ResponseValue implements UseCase.ResponseValue {
      
            private final Statistics mStatistics;
      
            public ResponseValue(@NonNull Statistics statistics) {
                mStatistics = checkNotNull(statistics, "statistics cannot be null!");
            }
      
            public Statistics getStatistics() {
                return mStatistics;
            }
        }
      

    这种方式提供了一种规范,可扩展、统一封装,这样就可以彻底将数据请求相关的屏蔽掉,如果以后更换请求接口,也不会影响到 UseCase 的使用,更不会影响 View 层了,所以比较推荐这种方式。

    • 关于 checkNotNull 方式:

        public GetStatistics(@NonNull TasksRepository tasksRepository) {
            mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
        }
      

    强烈建议使用 google 的 checkNotNull 这种方式,必须保证不会 null,这个是 Google 的另一库 guava,建议学习下,有很多值得我们学习的地方,比如:字符串操作、I/O等,这里就不展开说了。

    • 关于 onError 处理:
     public void onFailure() {
        getUseCaseCallback().onError();
     }
    

    没有错误信息肯定是不行的,官方也建议我们应该包含一些错误信息,例如:异常信息等;

    Demo

    Demo android-architecture-todo-mvp 是对官方 todo-mvptodo-mvp-clean 精简完的 Demo,只包含了了最基本的 MVP 思想。

    参考文章

    以下是自己在学习过程中参考的资料

    相关文章

      网友评论

        本文标题:Google MVP 你也可以运用自如

        本文链接:https://www.haomeiwen.com/subject/xflasttx.html