前言
很早之前就听说过android MVP的模式,也看过许许多多的文章,但是众说纷纭,每个人有每个人的理解,如果光看,可能并不能很深刻的理解。但是作为android界的权威,Google出了一个MVP的官方例子。若是从这个例子来看MVP模式,或许会有不一样的感悟呢?多说无益,下面开始。
代码准备
Github上打开googlesamples/android-architecture,打开分支,选择todo-mvp
(Basic Model-View-Presenter architecture),然后下载zip,解压后导入到AS中。
代码分析
首先贴一张官方的MVP示意图:
在分析代码之前,我们先简单的运行一下App,大致有一个感觉,App里有哪些功能。
ok,下面进入到代码里,先上一下代码结构图:
可以看到分包是根据模块进行的分包,通过gif图大概可以知道分为添加(编辑)、统计、详情、主页List。
本文只为了分析mvp的使用,所以我选取最简单的AddEditTask来进行分析。
M
M主要是位于data包下面的类,Task是基本的bean,涉及到数据的相关操作由接口TasksDataSource
体现。
1 | public interface TasksDataSource { |
V
首先是V的基类:
1 | public interface BaseView<T> { |
然后看到AddEditTaskContract
:
1 | public interface AddEditTaskContract { |
这个类将V、P整合在了一起,这样做的好处是可以很方便的看到V、P都有哪些方法,方便后面修改。其中的View
则是BaseView的下一层接口,它定义了View相关的一些方法。
P
P的基类:
1 | public interface BasePresenter { |
然后在AddEditTaskContract
中我们也可以看到P的具体声明。
MVP综合分析
MVP大致的代码便是如此了,下面来看具体的实现。
在AddEditTaskActivity
的onCreate()方法中,我们重点看到这一句代码:
1 | new AddEditTaskPresenter( |
可以知道,这句代码便是创建具体的P了。
来看下一下AddEditTaskPresenter
的代码:
1 | /** |
我们通过其构造函数,传入了一个addEditTaskFragment对象,通过其构造函数的方法,我们可以猜测:AddEditTaskFragment便是具体的V了。
并且注意mAddTaskView.setPresenter(this);
这句代码,即是在P创建的时候,V、P便实现了绑定。
看到AddEditTaskFragment
代码:
1 | public class AddEditTaskFragment extends Fragment implements AddEditTaskContract.View { |
通过前面的gif图,可以猜测P中必定是有一个保存Task的方法,即saveTask
方法,在我们点击悬浮按钮的时候会触发。即我们的操作(业务逻辑相关)会由P来执行。
看到P中saveTask
的具体实现,他会判断当前是否是一个新任务,若是则调用createTask
创建新的Task,若标题与内容都为空,则会回调V的showEmptyTaskError
方法来显示相关的UI,若不为空,则执行M的操作:mTasksRepository.saveTask(newTask);
保存相应的数据,然后回调V的showTasksList
方法来显示相关UI。若不是一个新的Task(编辑),则调用updateTask
,执行M操作mTasksRepository.saveTask
来操作数据。
至此,一个完整的业务操作(新建或编辑一个新的Task)分析完毕。可以看到在V中,我们只调用P的相关的接口,然后实现上层V的接口就可以了。由P来调用M中的方法,来操作数据,然后通过回调来使V展示相应的界面。V与M完全分离,整套业务都由P来执行。
最后上一张分析图:
MVP的优缺点
优点:
- 解耦。实现了Model和View真正的完全分离,再也不是Activity中一大坨代码了。
- 清晰。模块职责划分明显,层次清晰。
- 测试。在使用MVP的项目中Presenter对View是通过接口进行,在对Presenter进行不依赖UI环境的单元测试的时候。可以通过模拟一个View对象,这个对象只需要实现了View的接口即可。然后注入到Presenter中,单元测试的时候就可以完整的测试Presenter应用逻辑的正确性。
- 组件化。在MVP当中,View不依赖Model,这样就可以让View从特定的业务场景中脱离出来,可以说View可以做到对业务完全无知,它只需要提供一系列接口提供给上层操作,这样就可以做到高度可复用的View组件。
缺点:
- 新增很多接口类,额外的代码复杂度及学习成本。
- Presenter中除了业务逻辑以外,可能还有大量的与业务无关的数据操作逻辑,会导致Presenter比较臃肿。
测试
在代码中,Google已经写好了测试代码:
1 | public class AddEditTaskPresenterTest { |
来执行一下吧:
可以看到测试成功。
那么假设我们采用传统的开发模式,代码全在Activity里,要怎么样测试呢?噢,想想就觉得头大了,是吗?
总结
通过此次Google官方例子的学习分析,让我对MVP模式有了更清晰的认识,并且我认为MVP模式的实用性很高。虽然它增加了额外的代码,但是它带来的好处是不言而喻的。在今后的开发中,我想我会尝试着使用它。