MVP模式简单讲解,通俗易懂

article/2025/9/23 3:24:22

了解 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
  1. Model: 数据层,负责与网络层和数据库层的逻辑交互。
  2. View: UI层,显示数据, 并向Presenter报告用户行为。
  3. 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,至少需要经历以下步骤:

  1. 创建 IPresenter 接口,把所有业务逻辑的接口都放在这里,并创建它的实现 PresenterCompl(在这里可以方便地查看业务功能,由于接口可以有多种实现所以也方便写单元测试)。

  2. 创建 IView 接口,把所有视图逻辑的接口都放在这里,其实现类是当前的 Activity/Fragment。

  3. 由UML图可以看出,Activity 里包含了一个 IPresenter,而 PresenterCompl 里又包含了一个 IView 并且依赖了 Model。Activity 里只保留对 IPresenter 的调用,其它工作全部留到 PresenterCompl 中实现。

  4. 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 兼顾着 ControllerView,这使得其代码分分钟上千行(本人深受其害),这使得代码难以理解难以维护,看到这样的 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 里面,比如你可能从网络下载一张图片,在下载成功的回调里把图片加载到 ActivityImageView 里面,所以异步任务保留着对 Activity 的引用。

这样一来,即使 Activity 已经被切换到后台(onDestroy 已经执行),这些 异步任务 仍然保留着对 Activity 实例的引用, 所以系统就无法回收这个 Activity 实例了,结果就是 Activity Leak

Android 的组件中,Activity 对象往往是在堆(Java Heap)里占最多内存的,所以系统会优先回收 Activity 对象, 如果有 Activity Leak,APP很容易因为内存不够而 OOM

采用 MVP模式,只要在当前的 ActivityonDestroy 里,分离异步任务对Activity 的引用,就能避免 Activity Leak
 

总结:

以上就是 MVP的简单实现,可能示例代码太简单无法体现 MVP的优势,但是理解了 MVP的思路 在项目中使用 MVP 就才能够真正体验到 MVP 带来的好处优势。


http://chatgpt.dhexx.cn/article/hRHQsYyF.shtml

相关文章

MVP框架模式

一、基本概念 MVP是Model-View-Presenter的简称,即模型-视图-表现层的缩写。MVP是由MVC模式进化而来的,MVP改进了MVC中的控制器过于臃肿的问题。 与MVC一样,MVP将应用程序的数据处理、数据显示和逻辑控制分开,用一种业务逻辑、数…

分析几个面试题:==和===;绑定事件;正则表达式

今天也是我学后端的朋友给我发了三个前端的面试题,这里我们试着分析一波。 目录 1、和的含义是什么,又有什么区别呢? (1)赋值: (2)相同: (3)…

前端面经总结

HTML及浏览器 对栅栏布局的理解 栅格化布局中的元素:column列,row行,gutter列之间的距离,container容器 栅格是否可以嵌套 canvas和svg的区别 SVG: SVG 是一种使用 XML 描述 2D 图形的语言。 在 SVG 中,…

前端深入学习

但是面试中必考的点且占比非常大的有前端基础和算法。 决定你是否能拿sp offer(高薪offer)以及是否进名企的是项目和算法。 absolute 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。 元素的位置通过 “left”, “to…

web前端常用词汇

html中的单词 Network [netwɜːk] 网络 General [dʒen(ə)r(ə)l] 一般的,大体的 Request [rɪkwest] 请求 Response [rɪspɒns] 响应 Headers [hedəz] 标题 HyperText [haɪpətekst] 超文本 Transfer [trnsfɝ] 传递 Protocol [prəʊtə…

前端html、css、JavaScript---硬核知识汇总

前端HTML篇 硬核!一篇文章教你阅遍html。 声明:本篇文章只是一个刚开始学习后端开发的菜鸟汇总完成的 JavaWeb学习前导html篇,所以专业性肯定不如前端人员,但用于学习后端开发足够了,刚接触html的童鞋拿来快速了解ht…

前端面试题总结(转载)

DOM结构 —— 两个节点之间可能存在哪些关系以及如何在节点之间任意移动1.DOM中两个节点存在的关系无非3种:1.1.包含与被包含,IE率先引入的contains()方法可检测,例 A.contains(B),即检查节点B是否是节点A的子节点,返回布尔值&…

前端三件套知识点

html 常用插件 文件比较 常用快捷键 ctrl f 查找当前页面的内容 !后按table 或者 html:5 代码模板快捷键 altb调试快捷键 ctrlk ctrlt改颜色主题 altshifta注释快捷键 html基础概念 一、 WEB标准的概念及组成 WEB标准不是某一个标准,而是一系列标准的集合。 …

php前端搜索功能,JavaScript实现前端实时搜索功能的代码分享(图)

这篇文章主要为大家详细介绍了JavaScript实现前端实时搜索功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 大部分页面都具备搜索功能。而作为前端,我们的目的只是将用户输入的内容返回给后台而后呈现反馈数据给用户,具体实…

前端实时搜索功能

** 大部分页面都具备搜索功能。而作为前端&#xff0c;我们的目的只是将用户输入的内容返回给后台而后呈现反馈数据给用户&#xff0c;具体实现如下&#xff1a; ** 1.基本布局&#xff1a; <div class"searcher"><p class"searcher-main">…

适合后端开发人员的html笔记

1html 锚点 <a href"#bottom">跳转到底部</a> <div class"aa"></div> <a href"#" id"bottom">跳转到顶部</a> img 图片标签 h1:一级标题块级元素其他的都是行内元素 img同时具备行内元素和块级…

【JavaScript】 一万字 JavaScript 笔记(详细讲解 + 代码演示 + 图解)

文章目录 变量 变量声明的提升数据类型Typeof运算符数据类型转换 表达式与运算符 隐式类型转换toFixed(a)方法保留a位小数关系运算符短路求值流程控制语句 数组函数DOMBOM面向对象 变量 一个变量只定义但没有赋初值&#xff0c;默认值是 undefined定义变量时必须写var&a…

前端面试 汇总整理

-----------------------------------------html css-------------------------------------------- 一.回流与重绘 回流一定引起重绘&#xff0c;重绘不一定回流 1.浏览器渲染机制 1&#xff09;浏览器采用流式布局。 2&#xff09;浏览器将html解析成DOM&#xff0c;css解析成…

JavaWeb——后端开发必备的JavaScript知识

JS学习 1.什么是JavaScript&#xff0c;有什么用&#xff1f; 答&#xff1a;JavaScript是网景公司发明的&#xff0c;运行在浏览器上的脚本语言&#xff0c;简称JS。 补充&#xff1a;网景公司现在没了&#xff0c;被美国在线收购了。 2.在HTML中嵌入JavaScript代码的三种方…

el-input中设置onkeypress事件是否匹配正则表达式显示输入内容的格式

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_BADAO_LIUMANG_QIZHI的博客-CSDN博客_若依前后端分离搭建 设置el-input的onkeypress事件限制输入内容是否匹配正则表达式。 注&#xff1a; 博客&a…

前端开发实习生面试总结

个人感觉面试官对实习生还是很友好的&#xff0c;大部分时候你答不上来都会引导你&#xff0c;最后还会点评你的不足&#xff0c;评价出来的那些问题确实是我自己的短板&#xff01;所以在整个过程中还是学到了很多&#xff01;&#xff01; 本人坐标南京&#xff0c;南京投的相…

datacenter 2

突然综合类又有新的事情了 页面能顺利打开了 但是好像值传不过去 之前不知道为什么输出了三十次 之前是判断两个不为4和200 然后else输出 现在改了之后只输入10次 但是出现通讯错误那个问题

数据中心与云数据中心

数据中心与云数据中心 数据中心&#xff08;DC&#xff0c;DataCenter&#xff09;是指在一个物理空间内实现信息的集中处理、存储、传输、管理等功能&#xff0c;它包括服务器、存储、网络等关键设备和这些关键设备运行所需要的环境因素&#xff0c;如供电、制冷、消防、监控等…

阿里云cassandra数据库datacenter查看

在使用阿里云的cassandra数据库时需要注意的是下图中的数据中心ID对应cassandra中的datacenter&#xff0c;而不是数据中心的名称&#xff01;&#xff01;&#xff01; 即SessionBuilder.withLocalDatacenter方法要使用阿里云cassandra官方文档中的数据中心ID public SelfT w…

英特尔固态硬盘测试软件,英特尔固态硬盘工具(Intel SSD Datacenter Tool)

英特尔固态硬盘数据中心工具Intel SSD Datacenter Tool是一个有用的命令行应用程序&#xff0c;特别适合管理 910 系列的英特尔SSD固态驱动器。如果用户的硬盘是英特尔的就需要下载一个这样的软件&#xff0c;软件能对硬盘进行检测和固件升级&#xff0c;有需要的可以下载使用。…