一、前言
首先声明一下,没有完美的架构,只要适合自己的项目,那就是最好的架构。
本例子是 MVP + Retrofit + RxJava 结合的例子,但本文的重点在于讲解 MVP 架构,所以涉及 Retrofit 和 RxJava 的部分将直接略过,默认读者已了解这两部分内容,如有需要,请自行查阅相关资料,网上资料很多。
史上最全 MVP 资料合集: Android MVP 详解(上)
RxJava 学习参考资料: 是时候学习 RxJava 了
二、MVC
早期项目中,我们会使用 MVC 架构来构建我们的项目,但是 MVC 架构的缺陷很明显,V 层和 C 层的职责混淆不清,很容易就会写成万能的 Activity,把业务逻辑、View 操作等一系列功能全放到 Activity 中来实现。
三、MVP
MVP 是 MVC 的进化版,它把 Controller 的职责从 Activity/Fragment 中拆分出来,作为 Presenter,这样就实现了 Activity/Fragment 和业务逻辑的解耦,更好地解决了数据与界面的关系。
- View 层: 对应于 Activity/Fragment,负责 View 的绘制以及与用户交互
- Presenter 层: 负责完成 View 与 Model 间的交互
- Model 层: 实体模型、与数据进行交互,对数据进行加工处理
1. 架构图
(上图由 ProcessOn 在线工具绘制)
2. 类图
(上图由 StarUML 绘制)
四、MVP 实践
1. 两个基类接口
首先定义两个接口,这两个接口分别是所有 View 和 Presenter 的基类: IBaseView
和 IBasePresenter
。
IBaseView
中主要定义一些通用的界面方法,如显示/隐藏进度条、显示提示信息等。IBasePresenter
中也可以定义一些通用的方法,如初始化方法等。
1 | public interface IBaseView { |
1 | public interface IBasePresenter { |
2. 定义契约类(接口)
使用契约类来统一管理 View 与 Presenter 的所有接口,这种方式使得 View 与 Presenter 中有哪些功能,一目了然,维护起来也很方便。
1 | public interface CookDetailContract { |
CookDetailContract
中的IView
接口定义了该界面(功能)中所有的 UI 状态情况,MainAcitivty 作为 View 层,实现了该接口,这样MainActivity
就只关注 UI 相关的状态更新。IPresenter
接口则定义了该界面(功能)中所有的用户操作事件,CookDetailPresenter
作为 Presenter 层,实现了该接口,这样CookDetailPresenter
就只关注业务层的相关逻辑,UI 的更新只需调用IView
的状态方法。
3. View 层(Activity/Fragment)
Activity/Fragment 是一个全局的控制者,负责创建 View 以及 Presenter 实例,并将二者联系起来。
在本例中,MainActivity 实现了 CookDetailContract.IView
接口,并在 onResume() 回调中创建 CookDetailPresenter
实例,CookDetailPresenter 的构造函数中实现了 View 和 Presenter 的关联。
在创建完 Presenter 后,调用 Presenter 的 getCookDetail() 方法获取相应的数据(如上图步骤①)。
在获取到 Model 层的数据后,Presenter 通过 IView 中的 updateCookDetail() 方法返回数据(如上图步骤④),Activity 获取数据后,将结果展示到界面上反馈给用户。
1 | mCookDetailPresenter = new CookDetailPresenter(MainActivity.this, this); |
4. Presenter 层
它实现了契约类中的 IPresenter
接口。
Presenter 翻译过来是主持人的意思,它做为 MVP 架构中最关键的一层,负责连接 View 层和 Model 层。比如控制显示/隐藏进度框、显示/隐藏空布局、错误布局,调用相应的 Model 层方法进行数据的获取,并在 Model 层返回数据后,将数据适配到 View 中展示。这样,便可以让 Model 层只关注数据相关的操作、也让 View 层只专注于界面的展示,让各个层级各司其职,相互协作。
1 | public class CookDetailPresenter implements CookDetailContract.IPresenter { |
5. Model 层
Model 层不只包含实体对象,更主要的功能是处理一切与数据相关的操作,如数据的获取、存储、数据状态变化都是 Model 层的任务,Presenter 会根据需要调用该层的数据处理逻辑(如上图步骤②),如有需要,Model 层会使用回调将数据传回 Presenter 层(如上图步骤③)。
1 | public class CookDetailManager { |
五、总结
使用 MVP 架构,缺点在于需要增加很多接口类、实现类,对于刚开始接口 MVP 架构的人来说,增加了不少的学习成本,看着一堆的类、一堆的接口,调来调去的,刚开始肯定会看晕。
但是当你熟悉了 MVP 架构,并掌握了它的精髓后,会发现虽然增加了很多代码,但是整体架构变得非常清晰,代码也可以多处复用。各个类和层的职责都非常明确且单一,后期的扩展,维护都会更加容易。整体的可测试性非常的好,UI 层和业务层可以分别进行单元测试。
项目代码已共享到 Github:AndroidMVPArchitecture
六、效果图
七、参考资料
PS:欢迎关注 SherlockShi 个人博客