首先附上自己写的一个MVP的demo,这是一个很标准的MVP,Github地址如下:

https://github.com/SilasGao/MVPDemo

首先MVP 是从经典的MVC架构演变而来,那我们是不是要先说下何为MVC模式?

系统C/S(Client/Server)三层架构模型:

1)视图层(View):一般采用XML文件对应用的界面进行描述,使用的时候可以直接引入,极为方便,可以的大大缩短开发时间,也可以使用JavaScript+HTML等的方式作为View层,当然这里需要进行Java和JavaScript之间的通信,幸运的是,Android提供了非常方便的通信实现。业务逻辑层(BLL):它的关注点主要集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计,也即是说它是与系统所应对的领域(Domain)逻辑有关,很多时候,也将业务逻辑层称为领域层。

2)控制层(Controller):Android的控制层的重任通常落在了众多的Acitvity的肩上,这句话也就暗含了不要在Acitivity中写代码,要通过Activity交割Model业务逻辑层处理。

3)模型层(Model):对数据库的操作、以及其他和数据有关的的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。就是应用程序中二进制的数据。

三层结构架构三层间的交互及作用如下图所示:

传统的MVC模式是很不错,我们也很熟悉,毕竟用了这么多年了。(突然想到之前去一家公司面试他问个HelloWord的Android项目是不是MVC,我说不是,他说回答错误,阿西吧!)

在Android项目上你会发现Activity的责任太重,什么东西都要放在Activity中,最终导致了Activity太过臃肿。虽然能抽的都抽出来了,但是会发现代码还是很多,试想下上千行代码还没有注释,能不晕?即使是自己写的,过些日子去看也有些晕晕的吧?

尤其代码敲完,一个月后需求又改了,从600、700行代码中找到要修改的地方也是要一点功夫的。

为了给Activity减轻压力,这时候MVP出现了!

MVP有什么好处,为什么要用MVP呢?

网上搜下一大堆MVP的各种好处,本人总结下主要有以下几点:

  • 代码解耦
  • 结构清晰
  • 可复用
  • 扩展性高
  • 方便进行单元测试

在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。

在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。而且,Presenter与具体的View是没有直接关联的,而是通过接口进行交互,从而使得在变更View时候可以保持Presenter的不变,可以多次复用。

在MVP里,应用程序的逻辑主要在Presenter来实现,其中的View是很薄的一层,只应该有简单的Set/Get的方法,用户输入和设置界面显示的内容,除此就不应该有更多的内容,绝不容许直接访问Model。

MVP主要解决就是把逻辑层抽出来成P层,要是遇到需求逻辑上的更改就可以只需要修改P层了或者遇到逻辑上的大改我们可以直接重写一个P也可以,很多开发人员把所有的东西都写在了Activity/Fragment里面这样一来遇到频繁改需求或者逻辑越来越复杂的时候,Activity /Fragment里面就会出现过多的混杂逻辑导致出错,所以MVP模式对于APP来对控制逻辑和UI的解耦来说是一个不错的选择。

上面说逻辑是在Presenter中处理的,假设这是一个登陆界面,如要输入账号密码,那么对账号密码的是否为空判断以及正则表达式判断等也要放在Presenter中,毕竟这些都是逻辑。

然后判断都成功的话(下面的操作都是在Presenter中进行的),先调用view层的方法,让ProgressDialog显示出来,然后调用model层的网络请求,结果的话在presenter中回调。在回调里面分别做ProgressDialog消失的处理,然后成功的话调用view层的方法,进入主界面。失败的话调用view层的方法,提示失败Toast之类的。

这就是最简单的一个流程了。

MVP是什么?怎么实现?

下图是本人Demo中的代码,就一个页面而已,然而一个页面竟然有这么多的类,11个,我勒个去,吓死宝宝了,这么多的类,说实话一个类就能解决了。不慌,下面让我们仔细分析为什么这么多类

首先介绍下每个类是干嘛的:

  • BuyBooActivity是我们的Activity
  • BaseActivity是Activity的基类
  • BasePresenter是Presenter的基类
  • BuyBookBean是我们的bean,也就是传说中的实体类,几个成员变量,自动生成一堆get、set方法的那个类
  • IBuyBookView也就是BuyBooActivity的接口
  • BuyBookPresenter也就是这个Actvity的Presenter
  • IBuyBookPresenter是BuyBookPresenter的接口
  • BuyBookModel是这个Activity的数据层
  • IBuyBookModel是BuyBookModel的接口
  • BuyBookAdapter是BuyBooActivity里面ListView的适配器
  • ValueCallBack,是一个通用的回调接口

这里接口都以I开头,每个model,presenter,还有Activity的view,都对应着一个接口,有些人可能会问了,干嘛写接口,一下多了这么多类,看的都懵逼了(比如以前有一个同事,他一直说项目用MVP,但是他不知道什么是MVP,直接把数据层写在了P中,估计是他以为bean才是model吧。我也不跟他说,毕竟人家工资比较高。说道这里突然想起了他以前的MVVM模式,第一个M是bean,他说这是model,第二个M以及一个V他说这是viewmodel,结果放的是所有的网络请求,最后一个V他放的是Aciivty和Fragment了。好了笑话说到这里,继续我们的主题)

为什么写接口?

问这个问题的童鞋应该去复习设计模式的六大基本原则了,我们要控制项目而不是项目控制我们,我们要进行的是面向接口的编程,用抽象(或者接口)搭建框架,用实现扩展细节。当然接口也不能滥用,都要看具体情况,这里本人是按照最高标准来写的。

Google官方MVP示例项目是把上面的IBuyBookPresenter以及IBuyBookView这2个接口放到了IBuyBookContract这个协议类中,实际上是一样的,这就看个人喜好了,各有各的优缺点。比如把本栗子的代码改成有协议类的这种就如下代码所示,看到了吧,其实是一样的。

public interface IBuyBookContract
{interface IBuyBookView{void showToast(String msg);void refreshAdapter();void onEmpty();}interface IBuyBookModel{List<BuyBookBean> getAdapterData();}
}

M(Model)

数据层,和MVC中的M一样,用来放数据的处理(比如网络请求,缓存等)。

V(View)

负责UI具体实现展现。比如Presenter派发过来一个动作是showDialog显示进度命令,那么我们这个View就负责实现具体UI。

P(Presenter)

负责处理业务逻辑代码,处理Model数据,然后将处理完的数据分发到View层。

下面开始贴代码讲解

先来讲View IBuyBookView

这里主要是包含了Activity的一系列关于UI操作,然后用我们的Activity是实现,这样Presenter就可以调用了。

public interface IBuyBookView {/*** 提示toast*/void showToast(String msg);/*** 刷新adapter*/void refreshAdapter();void onEmpty();
}

接下来讲Model IBuyBookModel BuyBookModel

主要是写了几个方法供BuyBookModel去实现

public interface IBuyBookModel {/*** 获取模拟数据*/void getTestData(ValueCallBack<List<BuyBookBean>> callBack);/*** 返回本地adapter数据* @return*/List<BuyBookBean> getAdapterData();
}

这里实现了IBuyBookModel,然后模拟了下网络请求,用随机来模拟请求成功与失败,所以如果有童鞋下载Demo发现进去怎么空白一片,那么请退出来多近几次,本人曾连续5次进去都是空白的,这运气也太背了吧。

public class BuyBookModel implements IBuyBookModel {private List<BuyBookBean> listData;public BuyBookModel() {this.listData = new ArrayList<>();}@Overridepublic void getTestData(final ValueCallBack<List<BuyBookBean>> callBack) {new Handler().postDelayed(new Runnable() {@Overridepublic void run() {List<BuyBookBean> list = new ArrayList<>();list.add(new BuyBookBean("赵云", 1, "09-27 09:11"));list.add(new BuyBookBean("赵云、隔壁老王、小王、典韦、貂蝉、林芳、曹操、刘备、关羽、黄忠、张飞、诸葛孔明", 10, "09-27 09:11"));list.add(new BuyBookBean("黄忠、孙权、大乔", 50, "09-27 09:11"));list.add(new BuyBookBean("大乔、小乔、貂蝉、孙尚香", 300, "09-27 09:11"));Random rd = new Random();int N = rd.nextInt(10);if (N > 5) {callBack.onSuccess(list);} else {callBack.onFail("拒绝请求");}}}, 1000);}@Overridepublic List<BuyBookBean> getAdapterData() {return listData;}
}

这里贴上楼上那个回调接口,这里用了泛型,为什么呢?为了多多复用。

public interface ValueCallBack<T> {void onSuccess(T t);void onFail(String code);
}

接下来讲Presenter BasePresenter IBuyBookPresenterBuyBookPresenter

这个是所有Presenter的基类,里面有个initData()方法,基本每个Presenter都要处理网络请求吧,所以我就弄了这么一个基类,至于为什么是抽象的而不是接口,这是因为抽象方便点吧,如果我们往抽象类中添加新的方法(该方法不是抽象的),可以给他提供默认的实现,而且不要修改现有的代码,但是如果是接口的话,就要修改现有的代码了。指不定我们以后要往这里加什么呢。

这里为什么用了个泛型?为了让人一看这个Presenter就知道这对应着哪个Activity,实际上这可以不加的,但是我觉得加上去更好。便于后来人也便于自己以后再来修改这个类。

public abstract class BasePresenter<T extends BaseActivity> {abstract void initData();
}

这里主要写了个方法,以供BuyBookPresenter实现

public interface IBuyBookPresenter {List<BuyBookBean> getAdapterData();
}

这里首先实现现了IBuyBookPresenter继承了BasePresenter,然后重写一些方法。这里的构造方法是重点,在构造方法中,我们需要传入一个IBookView,实际上我们的Activity已经实现IBookView了,所以这里实际上传的是具体的Activity,也就是this就行了。然后model我们可以直接new出来用,这里就new了。

在initData中我们是进行了具体的网络请求,网络请求我们是不是要弹一个Dialog出来,直接在这mView.loading();调用就行了。然后请求成功onSuccess()里面让Dialog消失,提醒适配器刷新。失败的话onFail()里面提示Dialog消失,然后ListView设置失败页面什么的。

public class BuyBookPresenter extends BasePresenter<BuyBookActivity> implements IBuyBookPresenter {private IBuyBookView  mView;private IBuyBookModel mModel;public BuyBookPresenter(IBuyBookView iBuyBookView) {this.mView = iBuyBookView;this.mModel = new BuyBookModel();}@Overridepublic List<BuyBookBean> getAdapterData() {return mModel.getAdapterData();}@Overridepublic void initData() {//在这里弹出loadingmModel.getTestData(new ValueCallBack<List<BuyBookBean>>() {@Overridepublic void onSuccess(List<BuyBookBean> buyBookBeen) {//在这里取消loading//简单数据操作可以在presenter里完成mModel.getAdapterData().addAll(buyBookBeen);mView.refreshAdapter();}@Overridepublic void onFail(String code) {//在这里取消loadingmView.showToast(code);mView.onEmpty();}});}
}

接下来讲我们的Activity BuyBookActivity BaseActivity

这是我们Acticity的基类,可以看到这里有个泛型,注意了,前方高能。这个泛型还必须继承BasePresenter,这个首先为了让人一看到这个Activity就知道对应着那个Presenter;其次最重要的就是为了下面那个成员变量basepresenter,我们写一个抽象的方法要求返回泛型T,而这个泛型T又继承了BasePresenter,那么我们就得到了具体Presenter的成员变量,可以直接用这个成员变量来调用Presenter中的方法了。

public abstract class BaseActivity<T extends BasePresenter> extends Activity {protected T basepresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(getLayout());initView();basepresenter = initPresent();onPrepare();}abstract T initPresent();abstract int getLayout();abstract void initView();abstract void onPrepare();
}

这个就是最终具体的Activity了,可以看到这里都没什么逻辑,基本都是一些重写的方法。

public class BuyBookActivity extends BaseActivity<BuyBookPresenter> implements IBuyBookView
{private ListView mListView;private BuyBookAdapter mAdapter;@OverrideBuyBookPresenter initPresent(){return new BuyBookPresenter(this);}@Overrideint getLayout(){return R.layout.activity_main;}@Overridevoid initView(){mListView = (ListView) findViewById(R.id.listview);}@Overridevoid onPrepare(){mAdapter = new BuyBookAdapter(this, basepresenter.getAdapterData());mListView.setAdapter(mAdapter);basepresenter.initData();}@Overridepublic void showToast(String msg){Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();}@Overridepublic void refreshAdapter(){mAdapter.notifyDataSetChanged();}public void onEmpty(){mListView.setEmptyView(null);}
}

最后虽然MVP模式有许多好处,但是有一个致命的缺点就是类太多,本来一个类最多变成了7个类,最少变成6个类(使用Contract协议类)。所以并不是所有的页面都要用MVP模式的,很简单的页面就没必要了,浪费时间是不是。

为什么MVP模式利于单元测试?

Presenter将逻辑和UI分开了,里面没有Android代码,都是纯纯的java代码。我们可以直接对Presenter写Junit测试

最后:这个MVP模式是非常基础了,只是给大家提供一下这个思路。

因为博客平时不是经常上,所以有问题需要及时回答的大佬们可以扫下这个。

MVP模式从入门到精通相关推荐

  1. mvp关联activity生命周期_Android MVP架构从入门到精通-真枪实弹

    Android MVP架构从入门到精通-真枪实弹 一. 前言 你是否遇到过Activity/Fragment中成百上千行代码,完全无法维护,看着头疼? 你是否遇到过因后台接口还未写而你不能先写代码逻辑 ...

  2. Android MVP架构从入门到精通-真枪实弹

    Android MVP架构从入门到精通-真枪实弹 一. 前言 二. MVC架构 1. MVC架构优缺点 A. 缺点 B. 优点 三. MVP架构 1. MVP架构优缺点 A. 缺点 B. 优点 四. ...

  3. Hive3入门至精通(基础、部署、理论、SQL、函数、运算以及性能优化)15-28章

    Hive3入门至精通(基础.部署.理论.SQL.函数.运算以及性能优化)15-28章 [Hive3入门至精通(基础.部署.理论.SQL.函数.运算以及性能优化)1-14章](https://blog. ...

  4. WPF MVVM从入门到精通1:MVVM模式简介

    WPF MVVM从入门到精通1:MVVM模式简介 原文:WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录 ...

  5. 《Linux指令从入门到精通》——4.2 Linux下的简单文字模式文本编辑器

    本节书摘来自异步社区<Linux指令从入门到精通>一书中的第4章,第4.2节,作者:宋磊 , 宋馥莉 , 雷文利著,更多章节内容可以访问云栖社区"异步社区"公众号查看 ...

  6. java mvp模式_MVP模式入门(结合Rxjava,Retrofit)

    本文MVP的sample实现效果: 老规矩,在说对MVP模式的理解之前还是要再谈谈MVC模式,了解了MVC的缺点.我们才知道为什么要用MVP. 关于MVC的图解,我在网上找到了一些图.如下: MVC模 ...

  7. Windows Embedded从入门到精通6月预告

    经历了九个月的时间,"Windows Embedded从入门到精通"系列课程终于到了收官阶段. 尽管很俗套,还是要感谢参与了这个系列课程的所有讲师,没有他们认真而执着的工作,就不会 ...

  8. meteor从入门到精通_我已经大规模运行Meteor一年了。 这就是我所学到的。

    meteor从入门到精通 by Elie Steinbock 埃莉·斯坦博克(Elie Steinbock) 我已经大规模运行Meteor一年了. 这就是我所学到的. (I've been runni ...

  9. 七夕福利 | 3D视觉从入门到精通系统学习教程

    写在前面 首先提前祝大家七夕快乐,感谢大家对工坊的陪伴与支持! 今天是七夕福利活动的最后一天,共100张券,已经送出去了60多张,还剩不到35张,大家可以抓住本次的活动机会,享受全年的最低价(优惠了7 ...

最新文章

  1. postgresql批量插入数据脚本_每日踩坑 2020-11-04 PostgreSQL 批量插入数据
  2. 常对象成员和常成员函数
  3. 北航出品,CVPR 安全AI大赛第二名:梯度细化提高对抗传递性
  4. qml tableview 滚动条加宽_qt qtableview 样式设置
  5. 【有限元分析】螺栓连接的几种分析方法
  6. 冯诺依曼计算机的弱点,冯。诺依曼型计算机的缺点及改进方法.doc
  7. Excel表格中如何将文本型改为数值型数据
  8. 刚刚,5G商用牌照正式发布,一共四张
  9. 深入理解裸机与RTOS开发模式
  10. 基于Vue.js的2048小游戏的设计与实现
  11. 随机矩阵 stochastic matrix
  12. 实业优则投资:危险的游戏
  13. 【淘宝API开发系列】获取商品详情,商品评论、卖家订单接口
  14. 北京理工大学-嵩天python语言程序设计-9-Python计算生态概览
  15. 【asp.net core 系列】5 布局页和静态资源
  16. 基于xilinx fpga的ofdm通信系统基带设计_基于嵌入式Wi-Fi处理器的无线系统设计...
  17. 最大堆和最小堆(数据结构)
  18. 排名:百度小程序 微信 + 支付宝 + 百度 + 头条 商城源码-拓客营销
  19. 数字图像处理 使用opencv+python识别七段数码显示器的数字
  20. 查看R包中包含的函数

热门文章

  1. 【有奖问卷】全球3万多名程序开发员都在参与的调研!丰富抽奖奖品+福袋奖励...
  2. 02_可执行文件生成过程和gcc参数介绍
  3. 5G 移动性管理状态
  4. 攻防世界MISC_base64stego
  5. ACM大一练习赛-第三场——A - 海森堡不确定原理
  6. [转] ICRA2022 SLAM相关论文整理
  7. app inventor:照相机调用、改变图片大小
  8. unity3d:Astar寻路,A星,A*,二叉堆优化Open表
  9. WiTricity科技助力中国电动汽车无线充电标准
  10. 案例25:基于Springboot论坛管理系统设计与实现开题报告