Android 实现一个 MVP 基础框架2019-12-19

这几年 MVP 在 Android 开发中已经开始被广泛使用,逐渐成为一种主流的设计思想。在 MVP 出现之前,我们使用最多的可能就是 MVC 了,那么我们为什么要使用 MVP,它解决了 MVC 使用中的那些痛点呢,那我们先从 MVC 说起。

一、浅谈 MVC

MVC 的全称是 Model-View-Controller,这三部分在 Android 中可以按照如下的层次划分:

Model(数据模型层)

主要负责网络请求、数据库等其它 I/O 操作

View(视图层)

主要包括 XML 布局文件(但功能较弱)

Controller(控制器层)

一般就是 Activity 或者 Fragment,负责 MVC 整个流程的调度、协作。但是由于 XML 的视图处理能力较弱,需要 Activity 或者 Fragment 承担部分视图层工作。

在 Android 中可以用网络请求的例子来梳理一下 MVC 的流程,例如,在 Activity(Controller)中通过一个 Button 点击事件调用 Model 层代码发起网络请求,当 Model 层网络请求成功响应后,在对应的回调函数中去更新 View 层的一个 RecyclerView。按照事件的流向,例子中 MVC 三部分的关系如下:

MVC

你可能还见过不同的 MVC 关系图,其实都是对的,因为不同的 MVC 实现可能会有不同的事件流向,选择适合自己的就行。

上图看起来层次结构很清晰,但还是存在一些问题的,虽然我们可以把网络请求的 Model 层解耦成一个单独的模块,但从网络请求的发起到响应结果的处理都集中在了 Activity 中,View 层的功能基本被弱化的可以忽略了,基本由 Activity 承担了,所以 Activity 同时承担了 Controller 和 View 层的职责,带来了耦合的问题,随着业务量的增加必然会导致 Activity 变的臃肿起来,增加维护成本。

那么面对这些问题 MVP 是如何应对的呢,它和 MVC 有何异同呢......

二、更好的 MVP

MVP 的全称是 Model-View-Presenter,它保留了 MVC 中的 View 层和 Model 层,用 Presenter 层替代了 Controller 层,在 Android 开发中三个层次的职责划分如下:

Model(数据模型层)

主要负责网络请求、数据库等其它 I/O 操作,和 MVC 中的  Model 层类似

View(视图层)

主要是 Activity、Fragment、XML布局文件

Presenter(控制器层)

自定义的 Presenter 类,类似于 MVC 中 Controller 的作用,是 MVP 中的核心,主要负责 Model 层和 View 层的交互

在 MVP 中 Activity、Fragment、XML都归属到了 View 层,即不存在 MVC 中 V、C层之间耦合的问题。在 MVC 中,Model 层功能代码的调用是在 Activity、Fragment 中进行的,但在 MVP 中这个职责将由 Presenter 去完成,然后将结果通过接口传递给 View 层,可以将 Model 层的实现、调用对 View 层隐藏起来,这样可以有效的降低  Activity、Fragment 的代码量,避免代码臃肿。

所以相比 MVC,MVP 的职责划分更加清晰,能够更好额解耦,但也会增加一些类文件。

下边是一个 MVP 的事件流向图,可以看到,在 MVP 中我们约定 Model 层和 View 层是不能直接通信的,而是通过 Presenter 层完成交互。

MVP

三、简单上手

理论性的东西说了一堆,难免有些瞌睡,先看一个使用的例子。

首先说明一下,我们的基础框架中用到了 RxJava2、Retrofit2

这里使用了玩Android的开放api接口进行测试,测试demo的目录结构如下:

demo


首先看WanAndroidApis接口,按照 Retrofit2 的要求,需要在里边声明网络请求的接口:


bean 目录对应接口返回 JSON 对应的类,就不多说了。

SampleContract是一个契约接口,这里约定了 Activity 需要实现的接口,以及接下来 Presenter 类中需要实现的业务方法:


SamplePresenterImpl类对应 MVP 中的 P,继承了我们基础框架中封装的BasePresenter类,同时实现了SampleContract中的Presenter接口:

最后来看MainActivity,继承了我们自己封装的基类BaseMvpActivity,同时实现了SampleContract中的View接口,并完成对应 Presenter 类的初始化:


到这里一个基本的使用就完成了,在 Fragment 中的使用也是类似的。解耦效果显而易见,职责划分更加清晰。

其实核心的就是每个有 MVP 需求的 Activity 或 Fragment 需要定义一个 Contract 契约接口与之对应,然后再实现一个具体的 Presenter 类。

更多实现细节可参考:https://github.com/SheHuan/EasyMvp

四、MVP 的封装过程

既然要封装,我们就需要尽可能的把通用的代码抽离出来,将一些常见的问题、需求在基础代码中处理好。封装后基础框架目录结构如下:

easymvp

1、Model 层

首先看Model层的封装,Model 层主要封装了基于 Retrofit2 的网络请求,即RetrofitManager类:

Retrofit2 和 RxJava2 是一对好搭档,可以方便的帮助我们完成网络请求的线程切换以及相应处理,所以RequestManager就是一个可以直接使用的网络请求类:


BaseObserver类相当于是网络请求的观察者类,可以用来监听网络请求的开始、完成、发生错误等:


在这里边我们可以按需显示耗时任务过程中的 Loading,以及异常提示 Toast。

RequestManager类还用到了一个ResponseConvert类,将BaseResponse响应根据接口约定的响应码进一步处理

由于测试代码使用了 玩Android 的api,对应的响应数据bean可以这样定义:

BaseResponse类的前两个字段需要根据自己接口的数据格式进行修改。

RequestManager类中还有一个ExceptionConvert类,当网络请求过程中遇到异常时,不会直接抛出异常,而是进一步转发异常信息,方便统一处理:

ExceptionHandler类会对异常信息进行统一的转换处理,如果需要定制部分异常提示信息则可以着手修改该类。

到此 Model 层的核心功能就实现了,也是我们封装过程中最复杂的部分。

2、Presente 层

核心的功能就是保存 RxJava 订阅时返回的Disposable对象,这一点在RequestManager的execute方法中已经有所体现。还有就是取消 RxJava 订阅关系,防止内存泄漏、发生异常。

3、View 层

Presenter类是在View层,即基类BaseMvpActivity、BaseMvpFragment中完成初始化以及Disposable和View接口对象的释放操作:

View 层的实现相对简单,BaseMvpFragment中我们实现了 Fragment 懒加载操作,在BaseActivity、BaseFragment中默认初始化了 ButterKnife 方便控件的绑定。

大家应该还见过其它结构的  MVP 代码,因为 MVP 更是一种设计思想,并没有限制性的规定你的代码必须要怎么写,所以只要我们的思路正确,适合自己的封装就是好的。

更多实现细节可参考:https://github.com/SheHuan/EasyMvp

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容