code小生,一个专注于 Android 领域的技术分享平台

作者:JYcoder
链接:https://www.jianshu.com/p/1f91cfd68d48
声明:本文是 JYcoder 原创,转发等请联系原作者授权。

安卓基础开发库,让开发简单点。
DevRing & Demo地址:https://github.com/LJYcoder/DevRing

学习/参考地址:
https://www.jianshu.com/p/91c2bb8e6369
http://www.jianshu.com/p/9d40b298eca9
http://blog.csdn.net/lmj623565791/article/details/46596109

MVP是什么?

Most Valuable Player(最有价值运动球员)? 不不不,虽然我很喜欢看nba,但此MVP非彼MVP。
这里的MVP是指安卓中的一种开发模式。
它将代码整体分为M(Model)、V(View)、P(Presenter)三层。

正经版:
M层(model):数据模型/处理层。负责数据处理、数据提供,如网络请求,数据库操作
V层(view):视图展示层。负责界面展示,如Activity,Fragment
P层(presenter):业务逻辑层。负责业务逻辑服务,是V层与M层间的桥梁

优化你的代码结构 --- MVP_第1张图片MVP示意图1

你也可以这样帮助理解下(餐厅版):
M层(model):厨师。负责做菜
V层(view):顾客。点餐吃饭
P层(presenter):服务员。提供下单、上菜等各种服务

优化你的代码结构 --- MVP_第2张图片MVP示意图2

与MVC模式的区别:
MVC中,V层与M层是可以互通的,而在MVP中V层与M层是不通的。
按餐厅版来说就是,MVC中顾客可以直接告诉厨师要吃什么菜,厨师做好后直接把菜端到你面前,而MVP中只能通过服务员来完成点餐到用餐的过程。

使用MVP有什么好处?

抽象些来说:
MVP可以降低代码耦合度,提高代码的结构清晰度、可读性、维护性和复用性。

具体些来说(参考JessYan的例子):
现在有这么一个需求:Activity中从网络获取数据然后展示在A控件上。
如果不用MVP的话,那就直接把获取展示等代码都写在Activity中,很快便可以写完。

但现在需求变动了:
1.要求加入缓存功能,如果本地有数据,则先从本地获取数据,然后再从网络获取最新数据进行替换
2.要求数据展示在B控件上而不是A控件。

如果代码都是你自己写的,那改起来还比较轻松,但假如是团队开发,代码不是你写的,你需要花时间把逻辑重新看一遍再开始改,而且如果改错的话,会影响之前已经写好的功能。

但使用MVP模式进行开发就不同了。由于它的分工结构清晰,V层仅负责数据展示,P层仅负责业务逻辑,M层仅负责数据获取/处理。所以改动起来就轻松很多。
对于变动的需求1:我们只需在P层加入逻辑判断(先从本地获取,再网络获取),然后M层增加一个从本地获取数据方法。
对于变动的需求2:我们只需在V层修改获取到数据后的展示方式,从控件A改成控件B。

当然还有可复用等优点,这里就不具体讲了。
至于"缺点"嘛,就是会相应地增加代码量。有得有失,但得大于失。

具体使用

以这么一个场景为例:
从网络获取“正在上映”的电影数据,获取成功则将数据在页面展示,获取失败则给出相应提示。

需要写四个部分:Model层,View层,Presenter层,接口

接口
负责“连接”MVP三层,以便方法调用、数据流动。同时也便于进行单元测试。

IView
View层接口,定义View层需实现的方法,P层通过该接口回调通知View层。

public interface IMovieView {    //成功获取到电影数据    void getMovieSuccess(List list, int type);    //获取电影数据失败    void getMovieFail(int status, String desc, int type);}

IModel
Model层接口,定义Model层需实现的方法,P层通过该接口调用M层获取/处理数据的方法。

public interface IMovieMoel{    //请求正在上映的电影数据    Observable getPlayingMovie(int start, int count);    ...}

Model层
实现IModel接口中的方法,负责数据的获取/处理。

public class MovieModel implements IMovieMoel{    @Override    public Observable getPlayingMovie(int start,int count) {        //提供数据源        return DevRing.httpManager().getService(MovieApiService.class).getPlayingMovie(start, count);    }    ...}

Presenter层
处理业务逻辑,调用M层获取数据,调用V层传递展示数据。

public class MoviePresenter {    private IMovieView mIView;    private IMovieModel mIModel;    public MoviePresenter(IMovieView iMovieView, IMovieMoel iMovieMoel) {        mIView = iMovieView;        mIModel = iMovieModel;    }    /**     * 获取正在上映的电影     *     * @param start 请求电影的起始位置     * @param count 获取的电影数量     * @param type  类型:初始化数据INIT、刷新数据REFRESH、加载更多数据LOADMORE     */    public void getPlayingMovie(int start, int count, final int type) {        DevRing.httpManager().commonRequest( mIModel.getPlayingMovie(start, count),         new CommonObserver>>() {            @Override            public void onResult(HttpResult> result) {                if (mIView != null) {                    mIView.getMovieSuccess(result.getSubjects(), type);                }            }            @Override            public void onError(int errType, String errMessage) {                if (mIView != null) {                    mIView.getMovieFail(errType, errMessage, type);                }            }        }, RxLifecycleUtil.bindUntilDestroy(mIView));    }    ...     /**     * 释放引用,防止内存泄露     */    public void destroy() {        mIView = null;    }}

View层
实现IView接口中的方法,对获取到的数据进行展示

public class MovieFragment implements IMovieView {    //获取电影数据成功的网络请求回调    @Override    public void getMovieSuccess(List list, int type) {        //成功,对数据进行展示        ....    }    //获取电影数据失败的网络请求回调    @Override    public void getMovieFail(int status, String desc, int type) {        //失败,界面上做出相应提示        ...    }}

完成以上几步后,在View层初始化时,调用Presenter层方法即可。

@Overrideprotected void initData() {      mPresenter = new MoviePresenter(this, new MovieModel());      mPresenter.getPlayingMovie(start, mCount, type);}

还有一点需注意:
如果Presenter层持有了View层的引用,那么记得在V层销毁时,把Presenter层中对View层的引用置null,避免View层回收失败导致内存泄漏。

@Overridepublic void onDestroy() {     super.onDestroy();     if (mPresenter != null) {          mPresenter.destroy();          mPresenter = null;     } }

MVP相关

从google todo-mvp示例再次学习MVP

一步一步带你认识 MVP+Retrofit+Rxjava 并封装(二)


优化你的代码结构 --- MVP_第3张图片

2018.04.20


更多相关文章

  1. Android之动画(Java代码实现)1
  2. Android中使用XmlSerializer拼装XML数据
  3. 【第一行代码】Android日志工具
  4. android:sqlite 数据库的事务详解
  5. Android 本地代码中的LIKELY和UNLIKELY宏
  6. Android移动应用基础学习——第四章数据存储
  7. Cocos2dx android 部分代码的理解
  8. 【Android】内嵌html页面与native代码简单交互
  9. android学习笔记之十一数据存储(Shared Preferences、SQLite)

随机推荐

  1. Android(安卓)AIDL的实现
  2. Android系统密度的修改
  3. 去除MTK Android(安卓)自带Launcher用自
  4. AndroidStuio快速发布开源项目到Jcenter/
  5. 站外地图--程序员
  6. 获取Android(安卓)ics源码
  7. Android开发——Android(安卓)Studio下使
  8. android中google“定位查询”
  9. android的makefile 特有的 dd
  10. Android仿360悬浮小球自定义view实现示例