优化你的代码结构 --- MVP

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层间的桥梁

640?wxfrom=5&wx_lazy=1MVP示意图1

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

640MVP示意图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<MovieRes> 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<HttpResult<List<MovieRes>>>() {
           @Override
           public void onResult(HttpResult<List<MovieRes>> 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<MovieRes> list, int type) {
       //成功,对数据进行展示
       ....
   }

   //获取电影数据失败的网络请求回调
   @Override
   public void getMovieFail(int status, String desc, int type) {
       //失败,界面上做出相应提示
       ...
   }
}

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

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

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

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

MVP相关

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

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


640


猜你喜欢

转载自blog.csdn.net/H176Nhx7/article/details/79988345
MVP
今日推荐