MVP模式简单讲解,通俗易懂
了解 MVP 和 MVC 的区别
https://baike.baidu.com/item/MVP/3714550?fr=aladdin
什么是MVP:
MVP 是 MVC 的变种,其实是一种升级。要说 MVP 就要说说 MVC,在 MVC 中 Activity 其实是 View层级,但是通常在使用中 Activity即是View也是Controller,并没有将 View层 和 Controller层 进行分离, 耦合度大大提高,非常不利于项目的管理。这时候 MVP 就应运而生了。
MVP分为三层
- Model
- View
- Presenter
- Model: 数据层,负责与网络层和数据库层的逻辑交互。
- View: UI层,显示数据, 并向Presenter报告用户行为。
- Presenter: 从Model拿数据,应用到UI层,管理UI的状态,响应用户的行为。
- Activity 在项目中是一个全局的控制者,负责创建 view 以及 presenter 实例,并将二者联系起来。
MVP模式的核心思想
MVP 把 Activity 中的 UI逻辑 抽象成 View接口,把 业务逻辑 抽象成 Presenter接口,Model类 还是原来的 Model。
在 MVP 模式中 Activity 的功能就是响应生命周期和显示界面,具体其他的工作都丢到了 Presenter层 中进行完成,Presenter 其实是 Model层 和 View层 的桥梁。
具体的 MVP 的好处还有很多,就不详细介绍了,下面看看如何使用 MVP。
上面一张简单的 MVP 模式的 UML图,从图中可以看出,使用 MVP,至少需要经历以下步骤:
创建 IPresenter 接口,把所有业务逻辑的接口都放在这里,并创建它的实现 PresenterCompl(在这里可以方便地查看业务功能,由于接口可以有多种实现所以也方便写单元测试)。
创建 IView 接口,把所有视图逻辑的接口都放在这里,其实现类是当前的 Activity/Fragment。
由UML图可以看出,Activity 里包含了一个 IPresenter,而 PresenterCompl 里又包含了一个 IView 并且依赖了 Model。Activity 里只保留对 IPresenter 的调用,其它工作全部留到 PresenterCompl 中实现。
Model 并不是必须有的,但是一定会有 View 和 Presenter。
通过上面的介绍,MVP 的主要特点就是把 Activity 里的许多逻辑都抽离到 View 和 Presenter 接口中去,并由具体的实现类来完成。这种写法多了许多 IView 和 IPresenter 的接口。
在某种程度上加大了开发的工作量,刚开始使用 MVP 的小伙伴可能会觉得这种写法比较别扭,而且难以记住。其实一开始想太多也没有什么卵用,只要在具体项目中多写几次,就能熟悉 MVP模式 的写法,理解意图,以及享受其带来的好处。
MVP的使用:
理论说了这么多其实没有什么卵用,下面就来在代码中看看如何使用吧。
先来看看项目中代码结构,结构图如下:
通过代码结构图可以看到看出 MVP 结构层级分明(在项目中使用 MVP 最好通过模块进行分层这样便于管理且结构清晰)。
View层代码
ILoginView 接口代码如下:
public interface ILoginView {public void onClearText();public void onLoginResult(Boolean result, int code);
}
可以看出 ILoginView 只是一个接口,简单的定义了两个方法。
看看 ILoginView 的实现类也就是我们的 LoginActivity:
/*Model: 数据层,负责与网络层和数据库层的逻辑交互。View: UI层,显示数据, 并向Presenter报告用户行为。Presenter: 从Model拿数据,应用到UI层,管理UI的状态,响应用户的行为。*/
// Activity 在项目中是一个全局的控制者,负责创建 view 以及 presenter 实例,并将二者联系起来。
public class LoginActivity extends AppCompatActivity implements ILoginView, View.OnClickListener {private Button mLogin;private Button mClear;private EditText mName;private EditText mPassWord;ILoginPresenter loginPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);mLogin = (Button) findViewById(R.id.btn_login);mClear = (Button) findViewById(R.id.btn_clear);mName = (EditText) findViewById(R.id.et_name);mPassWord = (EditText) findViewById(R.id.et_password);mLogin.setOnClickListener(this);mClear.setOnClickListener(this);loginPresenter = new LoginPresenterCompl(this);}@Overridepublic void onClick(View v) {int id = v.getId();String name = mName.getText().toString();String password = mPassWord.getText().toString();switch (id) {case R.id.btn_login:loginPresenter.doLogin(name, password);break;case R.id.btn_clear:loginPresenter.clear();break;}}@Overridepublic void onClearText() {mName.setText("");mPassWord.setText("");Toast.makeText(this, "clear", Toast.LENGTH_LONG).show();}@Overridepublic void onLoginResult(Boolean result, int code) {mLogin.setEnabled(true);mClear.setEnabled(true);if (result) {Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show();}}
}
在 LoginActivity 中我们可以看到,LoginActivity 实现了 ILoginView 接口,实现了未实现的方法,在代码中可以看出 LoginActivity 并没有做一些逻辑处理工作,数据处理的工作都是调用 ILoginPresenter 完成的。
Presenter代码
下面就来看看 ILoginPresenter:
public interface ILoginPresenter {public void clear();public void doLogin(String name, String password);
}
也是简单的接口定义两个未实现的方法。
看看其实现类 LoginPresenterCompl:
public class LoginPresenterCompl implements ILoginPresenter {private ILoginView loginView;private User user;public LoginPresenterCompl(ILoginView view) {loginView = view;user = new User("张三", "123456");}@Overridepublic void doLogin(String name, String password) {boolean result = false;int code = 0;if (name.equals(user.getName()) && password.equals(user.getPassword())) {result = true;code = 1;} else {result = false;code = 0;}loginView.onLoginResult(result,code);}@Overridepublic void clear() {loginView.onClearText();}
}
该实现类也比较简单,定义了用户名是张三,密码是123456的一个登陆用户,然后进行登陆和清除的操作。
Model层代码
User 的代码如下:
public class User {private String name;private String password;public User(String name,String password){this.name = name;this.password = password;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
OK,这就完成了最简单的 MVP模式 了。
看完上述 MVP 的代码后可能有的同学会说一个简单的登陆就是简单的验证用户名和密码为什么要设计的这么复杂,可能有人会觉得还没有以前的写法简单呢。但是这只是一个简单的实现 MVP 的例子。
当项目越来越大,代码越来越多的时候就能够真正的体现出 MVP模式 的优势了。
知道了什么是 MVP 也知道了如何在项目中使用 MVP,那MVP的优势到底有哪些呢?
MVP的优势:
使Activity代码更加简洁
在传统的项目中 Activity 兼顾着 Controller 和 View,这使得其代码分分钟上千行(本人深受其害),这使得代码难以理解难以维护,看到这样的 Activity 就想吐。
使用 MVP 之后,Activity 就能瘦身许多了,基本上只有 FindView、SetListener 以及 Init 的代码。其他的就是对 Presenter 的调用,还有对 View接口 的实现。这种情形下阅读代码就容易多了。
而且你只要看 Presenter 的接口,就能明白这个模块都有哪些业务,很快就能定位到具体代码。Activity 变得容易看懂,容易维护,以后要调整业务、删减功能也就变得简单许多。
方便进行单元测试
一般单元测试都是用来测试某些新加的业务逻辑有没有问题,如果采用传统的代码风格,我们可能要先在 Activity 里写一段测试代码,测试完了再把测试代码删掉换成正式代码,这时如果发现业务有问题又得换回测试代码,咦,测试代码已经删掉了!好吧重新写吧……
MVP 中,由于业务逻辑都在 Presenter 里,我们完全可以写一个 PresenterTest 的实现类继承 Presenter 的接口,现在只要在 Activity 里把 Presenter 的创建换成 PresenterTest,就能进行单元测试了,测试完再换回来即可。万一发现还得进行测试,那就再换成 PresenterTest 吧。
避免Activity内存泄露
APP发生 OOM 的最大原因就是出现内存泄露造成APP的内存不够用,而造成内存泄露的两大原因之一就是 Activity泄露(Activity Leak)(另一个原因是 Bitmap泄露(Bitmap Leak))。
Java一个强大的功能就是其虚拟机的内存回收机制,这个功能使得Java用户在设计代码的时候,不用像 C++ 用户那样考虑对象的回收问题。然而,Java用户总是喜欢随便写一大堆对象, 然后幻想着虚拟机能帮他们处理好内存的回收工作。可是虚拟机在回收内存的时候,只会回收那些没有被引用的对象,被引用着的对象因为还可能会被调用,所以不能回收。
Activity 是有生命周期的,用户随时可能切换 Activity,当APP的内存不够用的时候,系统会回收处于后台的Activity的资源以避免 OOM。
采用传统的模式,一大堆异步任务和对UI的操作都放在 Activity 里面,比如你可能从网络下载一张图片,在下载成功的回调里把图片加载到 Activity 的 ImageView 里面,所以异步任务保留着对 Activity 的引用。
这样一来,即使 Activity 已经被切换到后台(onDestroy 已经执行),这些 异步任务 仍然保留着对 Activity 实例的引用, 所以系统就无法回收这个 Activity 实例了,结果就是 Activity Leak。
Android 的组件中,Activity 对象往往是在堆(Java Heap)里占最多内存的,所以系统会优先回收 Activity 对象, 如果有 Activity Leak,APP很容易因为内存不够而 OOM。
采用 MVP模式,只要在当前的 Activity 的 onDestroy 里,分离异步任务对Activity 的引用,就能避免 Activity Leak。
总结:
以上就是 MVP的简单实现,可能示例代码太简单无法体现 MVP的优势,但是理解了 MVP的思路 在项目中使用 MVP 就才能够真正体验到 MVP 带来的好处优势。
MVP模式简单讲解,通俗易懂相关推荐
- 简单易懂 MVP 模式
Android MVP 模式 [1] 也不是什么新鲜的东西了,我在自己的项目里也普遍地使用了这个设计模式.当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP 模式 的优势就充分显示出来了. ...
- 浅谈安卓中的MVP模式
端午放假,天气下雨,于是乎在家撸一下博客,本篇博客将为大家解析MVP模式在安卓中的应用. 本文将从以下几个方面对MVP模式进行讲解: 1. MVP简介 2. 为什么使用MVP模式 3. MVP模 ...
- Android之MVP 模式:简单易懂的介绍方式
转载:https://segmentfault.com/a/1190000003927200 Android MVP Pattern Android MVP 模式1 也不是什么新鲜的东西了,我在自己的 ...
- android mvp模式例子_ANDROID MVP 模式 简单易懂的介绍方式
Android MVP Pattern Android MVP 模式1 也不是什么新鲜的东西了,我在自己的项目里也普遍地使用了这个设计模式.当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP ...
- MVP 模式简单易懂的介绍方式
Android MVP 模式 1 也不是什么新鲜的东西了,我在自己的项目里也普遍地使用了这个设计模式.当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP 模式 的优势就充分显示出来了. MV ...
- 一个简单的MVP模式案例
1. 问题背景 首先需要清楚的一点是MVP模式的设计初衷是:为了解决在MVC模式中,过于复杂的逻辑和界面之间的交互中Activity的职责不单一的问题,Activity既充当了View层,又充当了Co ...
- gwt的mvp模式_GWT MVP变得简单
gwt的mvp模式 GWT Model-View-Presenter是用于大规模应用程序开发的设计模式. 它源于MVC,它在视图和逻辑之间进行划分,并有助于创建结构良好,易于测试的代码. 为了帮助像我 ...
- Java基础之泛型简单讲解(通俗易懂)
Java基础之泛型简单讲解(通俗易懂) 1. 前言 2. 简单例子对比理解 2.1 未使用泛型例子--ArrayList 2.2 使用泛型的例子 2.2.1 ArrayList 举例 2.2.2 Ha ...
- Android MVP模式介绍和讲解
作者:谭东 先给个MVP的出处链接:https://github.com/googlesamples/android-architecture/,出处就是google在github上的一个架构的开源例 ...
最新文章
- C++知识点杂记2——类成员指针、嵌套类和union
- 为学Linux,我看了这些书
- 安装 | Windows 10下基于Anaconda的TensorFlow详细安装步骤(续)——Pycharm运行tensorflow
- JQuery闭包,插件的写法
- spring-注解---IOC(3)
- C#自定义数字格式字符串
- mantis修改mysql端口_(功能篇)回顾Bug管理系统Mantis优化改造经历(示例代码)
- 【已经解决】TypeError: read_img() missing 1 required positional argument: ‘filename‘
- NSData的同步下载与NSConnection的同步下载
- java开发简历项目经验,面试必会
- Visio 2019/2016中文版零基础入门视频教程
- 深圳大学计算机考研教材,广东-深圳大学计算机考研院校初试科目及参考书汇总...
- 【MongoDB】索引属性 之 唯一索引
- 值得收藏的网站----安全
- 基于微型计算机系统的实时时钟设计,基于单片机的DS12C887时钟芯片应用研究
- 240Hz 1ms 电竞屏看起来怎么样 — ZOWIE XL2540 评测
- 操作系统简史(1)东方会有新的操作系统诞生吗?让历史告诉未来
- 从哈希表到MD5摘要算法
- 海南省教育厅关于普通高中综合实践活动课程实施的指导意见
- 电脑重装系统UEFI启动如何设置
热门文章
- 实现在树莓派的GPIO接口上用跳线(短路帽)轻松选择启用或者禁用overlayfs影子系统
- 新手用H5实现基础的echarts表格
- H5摇一摇遇到的问题
- 阿里云redis公网连接
- 【考研·数据结构】408真题 (2013年42题) 的两种解法】
- 35.Trie树:如何实现搜索引擎的搜索关键词提示功能
- Vuex和antv/g6实现在线绘制分析流程图功能
- 思科CEO罗卓克:将继续致力于将自动化、安全与云管理引入产品组合
- 淘宝AppKey申请操作说明
- 为什么无穷大总是0x3f3f3f3f而不是0x7fffffff?