浅谈安卓中的MVP模式

article/2025/9/23 1:27:23

端午放假,天气下雨,于是乎在家撸一下博客,本篇博客将为大家解析MVP模式在安卓中的应用。

本文将从以下几个方面对MVP模式进行讲解:

1.  MVP简介

2.  为什么使用MVP模式

3.  MVP模式实例

4.  MVP中的内存泄露问题



1.  MVP简介:

随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责。为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生。

MVP模式里通常包含4个要素:

(1)View:负责绘制UI元素、与用户进行交互(Android中体现为Activity);

(2)ViewInterface:需要View实现的接口,View通过View interfacePresenter进行交互,降低耦合,方便进行单元测试;

(3)Model:负责存储、检索、操纵数据(有时也实现一个Modelinterface用来降低耦合);

(4)Presenter:作为ViewModel交互的中间纽带,处理与用户交互的负责逻辑。


2.  为什么使用MVP模式


Android开发中,Activity并不是一个标准的MVC模式中的Controller的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。当我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中 View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由 Presenter处理).

 另外,回想一下你在开发Android应用时是如何对代码逻辑进行单元测试的?是否每次都要将应用部署到Android模拟器或真机上,然后通过模拟用户操作进行测试?然而由于Android平台的特性,每次部署都耗费了大量的时间,这直接导致开发效率的降低。而在MVP模式中,处理复杂逻辑的 Presenter是通过interfaceView(Activity)进行交互的,这说明了什么?说明我们可以通过自定义类实现这个 interface来模拟Activity的行为对Presenter进行单元测试,省去了大量的部署及测试的时间。


3.  MVP模式实例

好了,大致了解了MVP模式的基本概念之后,我们就使用MVP模式来写一个小例子。

包的结构如下图所示:                    效果展示:

                       

下面开始讲解mvp模式的步骤:

1) 创建view的接口类,根据业务定义抽象方法

<span style="font-size:18px;">public interface IUserView {//显示进度条void showLoading();//展示用户数据void showUser(List<User> users);}</span>
2) 创建model的接口类,根据业务定义抽象方法

其中定一个加载数据的方法,同时设置一个加载完成的监听,监听内设置抽象方法complete,用于加载完成后进行回调

public interface IUserModel {//加载用户信息的方法void loadUser(UserLoadListenner listener);//加载完成的回调interface UserLoadListenner{void complete(List<User> users);}
}

3)创建model的实现类,实现其中抽象方法,其中的user类是在bean包根据需求自行创建的

public class UserModelImpl implements IUserModel{@Overridepublic void loadUser(UserLoadListenner listener) {//模拟加载本地数据List<User> users = new ArrayList<User>();users.add(new User("姚明", "我很高", R.drawable.ic_launcher));users.add(new User("科比", "怒砍81分", R.drawable.ic_launcher));users.add(new User("詹姆斯", "我是宇宙第一", R.drawable.ic_launcher));users.add(new User("库里", "三分我最强", R.drawable.ic_launcher));users.add(new User("杜兰特", "千年老二", R.drawable.ic_launcher));if(listener != null){listener.complete(users);}}}

加载完数据,回调listener中的complete方法。

4) 创建present,在构造函数传入view的实现类,同时在其中new出model的实现类,创建一个方法load,实现view与model间通信的桥梁。

public class Presenter1 {//viewIUserView mUserView;//modelIUserModel mUserModel = new UserModelImpl();//ͨ通过构造函数传入viewpublic Presenter1(IUserView mUserView) {super();this.mUserView = mUserView;}
//加载数据public void load() {//加载进度条mUserView.showLoading();//model进行数据获取if(mUserModel != null){mUserModel.loadUser(new UserLoadListenner() {@Overridepublic void complete(List<User> users) {// 数据加载完后进行回调,交给view进行展示mUserView.showUser(users);}});}}
Load中,先调用mUserView.showLoading() 显示加载进度,然后是调用mUserModel.loadUser加载数据,其中要实现Listenner的complete方法,其中的逻辑就是用view将数据显示到界面,model的最后会回调listener中的complete方法,数据就显示在界面上了。

5) MainActivity显然是用来显示数据的,其中有一个listview,创建与其相关的两个布局文件activity_main.xml与item_user.xml,令MainActivity实现IUserView接口,并实现两个抽象方法,创建listview的适配器,重写构造函数,并利用viewHolder,复用convertView对其进行优化,最后创建Presenter,并调用其load方法,完成加载所有逻辑。

<pre name="code" class="java">public class MainActivity extends ActionBarActivity implements IUserView  {private ListView mListView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mListView = (ListView) findViewById(R.id.lv);      new Presenter1(this).load();}public void showUser(List<User> users) {//显示所有用户列表mListView.setAdapter(new UserAdapter(this,users));}@Overridepublic void showLoading() {Toast.makeText(this, "正在拼命加载中", Toast.LENGTH_SHORT).show();}
}

 

适配器:

public class UserAdapter extends BaseAdapter {private Context context;private List<User> users;public UserAdapter(Context context, List<User> users) {this.context = context;this.users = users;}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn users.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn users.get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {LayoutInflater inflater = LayoutInflater.from(context);ViewHolder viewHolder = null;//convertViewif (convertView == null) {convertView = inflater.inflate(R.layout.item_user, null);viewHolder = new ViewHolder();viewHolder.image = (ImageView) convertView.findViewById(R.id.iv_user);viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name);viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content);convertView.setTag(viewHolder);}else{viewHolder = (ViewHolder) convertView.getTag();}viewHolder.image.setImageResource(users.get(position).getPicid());viewHolder.name.setText(users.get(position).getName());viewHolder.content.setText(users.get(position).getContent());return convertView;}private static class ViewHolder {ImageView image;TextView name;TextView content;}}

这样,我们的小例子就写完了,效果如下:

体会MVP模式的优越性:

a) 假设我们不从本地获取用户数据了,改成从网络获取,只需要从新写一个model的实现类,并new 一个present,并在MainActivity中进行替换,就可以解决,我们模拟一下这种情况,发现修改十分方便,主界面建议使用MVP模式,它很好遵守了开闭原则。

b) 假设我不想用listview显示数据,想换成gridview,无需修改原来代码,只需要新建一个新的Activity来实现view,实现接口方法,同时使用gridview与新建一个与其对应的adapter即可,符合了开闭原则,不修改源码,而是进行扩展性修改。View与model解耦,可以发现我们写的Activity里面都是没有model的影子的,只有presenter.

public class GridActivity extends MvpBaseActivity<IUserView, GridPresenter> implements IUserView{private GridView mGridView;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_grid);mGridView = (GridView) findViewById(R.id.gv);mPresenter.load();}@Overridepublic void showLoading() {// TODO Auto-generated method stubToast.makeText(this, "正在拼命加载中", Toast.LENGTH_SHORT).show();}@Overridepublic void showUser(List<User> users) {// TODO Auto-generated method stubmGridView.setAdapter(new UserAdapter(this,users));}@Overrideprotected GridPresenter createPresenter() {// TODO Auto-generated method stubreturn new GridPresenter();}}

public class Presenter2 {//viewIUserView mUserView;//modelIUserModel mUserModel = new UserModelImpl2();//ͨ通过构造函数传入viewpublic Presenter2(IUserView mUserView) {super();this.mUserView = mUserView;}//加载数据public void load() {//加载进度条mUserView.showLoading();//model进行数据获取if(mUserModel != null){mUserModel.loadUser(new UserLoadListenner() {@Overridepublic void complete(List<User> users) {// 数据加载完后进行回调,交给view进行展示mUserView.showUser(users);}});}}}


4)MVP中的内存泄露问题

发现我们之前写的两个Acitivty有共性的地方,就是都new 了present,我们对代码进行抽取,提高代码的复用性。

在各个Activitty中Presenter有很多类型,所以在BaseActivitty中,也需要对Presenter进行抽取成BasePresenter,MVP中Presenter是持有view的引用的,所以BasePresenter中使用泛型

public abstract class BasePresenter<T> {}

在BaseActivitty中,Presenter的具体类型交给子类去确定,我们只提供一个生成Presenter的方法,这里多次用到了泛型,需要注意

public abstract class MvpBaseActivity<V,T extends BasePresenter<V>> extends ActionBarActivity {protected T mPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);//创建presentermPresenter = createPresenter();//内存泄露//关联ViewmPresenter.attachView((V) this);}protected abstract  T createPresenter();}

内存泄露分析:加入Model在请求网络加载数据,此时假设Activity由于内存不足,被GC回收,但是网络加载还未完成,则Presenter还存在,并持有Activity的引用,当网络加载数据完成,Presenter会使用Activity进行数据展现,而此时Activity已被回收,就发生了内存泄露,会报错,所以解决方法是:当view被回收,Presenter要解除与其的关联。

既然是Presenter解除与view的关联,那关联与解除的逻辑肯定是在Presenter中,使用弱引用包裹view,理由是,使用弱引用,当GC扫描到的时候,就会立即回收。所以对BasePresenter进行如下的修改:

public abstract class BasePresenter<T> {//当内存不足,释放内存protected WeakReference<T> mViewReference;

创建关联和解除关联的方法:

进行关联的逻辑:创建弱引用,并包裹view

解除关联的逻辑:判断,如果弱引用不为空,清空弱引用,并设置为空,彻底释放

//进行关联public void attachView(T view) {mViewReference = new WeakReference<T>(view);}//解除关联public void detachView() {if(mViewReference != null){mViewReference.clear();mViewReference = null;}}

暴露一个方法,用于其他类从弱引用中取出view

protected T getView() {return mViewReference.get();}
GridPresenter继承BasePresenter,进行对象抽象方法的实现

public class GridPresenter extends BasePresenter<IUserView>{//view//IUserView mUserView;//modelIUserModel mUserModel = new UserModelImpl();/*public GridPresenter(IUserView mUserView) {super();this.mUserView = mUserView;}*///加载数据public void load() {//加载进度条//mUserView.showLoading();getView().showLoading();//model进行数据获取if(mUserModel != null){mUserModel.loadUser(new UserLoadListenner() {@Overridepublic void complete(List<User> users) {// 数据加载完后进行回调,交给view进行展示//mUserView.showUser(users);getView().showUser(users);}});}}}

然后对BaseActivity进行修改:

public abstract class MvpBaseActivity<V,T extends BasePresenter<V>> extends ActionBarActivity {protected T mPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);//创建presentermPresenter = createPresenter();//内存泄露//关联ViewmPresenter.attachView((V) this);}protected abstract  T createPresenter();@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();mPresenter.detachView();}
}

oncreate方法中关联view,onDestroy方法中对关联进行清除,所有关于内存泄露的逻辑就完成了,好了,对MVP模式的分析到此就结束了,更多的应用得大家自己在项目中对该模式进行运用,并不断进行总结。











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

相关文章

Android MVP模式 入门

1.前言 近些年来&#xff0c;Android架构模式有很多&#xff0c;我们比较熟知的有MVC&#xff0c;MVP以及MVVM&#xff0c;目前Android市场中使用最多的应该是MVP架构&#xff0c;虽然MVVM结合DataBing看似更加方便&#xff0c;但在一般公司中使用的还是比较少。其实模式这种东…

MVP模式实例解释

为什么在UI层包含太多的逻辑是很糟糕的&#xff1f;在既不手动运行应用程序&#xff0c;也不维护丑陋的自动执行UI组件的UI运行者脚本(runner script)的情况下&#xff0c;位于应用程序UI层中的代码是非常难于调试的。虽然这本身就是一个很大的问题&#xff0c;一个更大的问题是…

Android开发之MVP模式

前言&#xff1a;在之前的开发中一直用的是mvc模式搭建的项目&#xff0c;所以我对于mvp也一直只是停留在理论和demo阶段上。正好现在的项目是被小伙伴借助dragger搭建的mvp模式的结构&#xff0c;所以就想着总结整理一下mvp模式的东西并写出来&#xff0c;也算是作为自己使用了…

MVP模式与MVC模式

源地址&#xff1a;http://www.cnblogs.com/cuihongyu3503319/archive/2009/01/09/1372820.html MVP模式与MVC模式(转) MVP 是从经典的模式MVC演变而来&#xff0c;它们的基本思想有相通的地方&#xff1a;Controller/Presenter负责逻辑的处理&#xff0c;Model提供数据&#x…

MVP模式从入门到精通

首先附上自己写的一个MVP的demo&#xff0c;这是一个很标准的MVP&#xff0c;Github地址如下&#xff1a; https://github.com/SilasGao/MVPDemo 首先MVP 是从经典的MVC架构演变而来&#xff0c;那我们是不是要先说下何为MVC模式&#xff1f; 系统C/S(Client/Server)三层架构模…

MVP模式使用示例详解

什么是MVP模式? 这个MVP可不是腾讯游戏《王者荣耀》中的MVP。我们今天要讨论的MVP其实同MVC一样&#xff0c;是一种编程模式和思想&#xff0c;也许更准确地讲是一种架构。 MVP和MVC的区别 提到MVP模式&#xff0c;大家自然避免不了要和我们以前常用的MVC模式进行对…

MVP设计模式

Model–view–presenter (MVP) 是model–view–controller (MVC)设计模式派生出来的。MVP经常用来创建用户界面。 presenter是作为一个“中间人”的角色存在。在MVP中&#xff0c;所有页面显示逻辑都会被推送到presenter。 以下这张图是MVC模式的&#xff1a; MVP与MVC有着一…

Android中用到的MVP模式

参考&#xff1a;android架构设计—mvp模式封装 很简单&#xff0c;M&#xff1a;数据&#xff0c; V:界面&#xff0c; P:一个使唤数据(M)和界面(V)干活的大管家。 特点&#xff1a;在P的管理下&#xff0c;P可以直接支配V和M做一些事情。但是V&#xff0c;与M&#xff0c;你…

Android MVP模式 简单易懂的介绍方式

Android MVP Pattern Android MVP 模式1 也不是什么新鲜的东西了&#xff0c;我在自己的项目里也普遍地使用了这个设计模式。当项目越来越庞大、复杂&#xff0c;参与的研发人员越来越多的时候&#xff0c;MVP 模式的优势就充分显示出来了。 导读&#xff1a;MVP模式是MVC模式在…

Android MVP模式详解

一、MVP概述 MVP&#xff0c;全称 Model-View-Presenter&#xff0c;即模型-视图-层现器。 提到MVP&#xff0c;就必须要先介绍一下它的前辈MVC&#xff0c;因为MVP正是基于MVC的基础发展而来的。两个之间的关系也是源远流长。 MVC&#xff0c;全称Model-View-Controller&am…

浅谈安卓MVP模式

本篇博文通过对google官方demo&#xff1a;https://github.com/googlesamples/android-architecture/tree/todo-mvp/的理解&#xff0c;用自己的demo更好的讲解mvp的概念&#xff0c;帮助大家如何针对一个Activity页面去编写针对MVP风格的代码。 一、MVP模式介绍 随着UI创建技…

简单易懂 MVP 模式

Android MVP 模式 [1] 也不是什么新鲜的东西了&#xff0c;我在自己的项目里也普遍地使用了这个设计模式。当项目越来越庞大、复杂&#xff0c;参与的研发人员越来越多的时候&#xff0c;MVP 模式 的优势就充分显示出来了。 MVP 模式是 MVC 模式在 Android 上的一种变体&#…

深入浅出——MVP模式

由于公司里的架构模式用到MVP&#xff0c;觉得自己还不够熟悉&#xff0c;决定在此理一理&#xff0c;并给大家一起总结下。 一 MVP模式介绍 MVP全称Model View Presenter。 MVP能够有效的降低View的复杂性&#xff0c;避免业务逻辑被塞进View中&#xff0c;防止View的代码变…

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

了解 MVP 和 MVC 的区别 https://baike.baidu.com/item/MVP/3714550?fraladdin 什么是MVP&#xff1a; MVP 是 MVC 的变种&#xff0c;其实是一种升级。要说 MVP 就要说说 MVC&#xff0c;在 MVC 中 Activity 其实是 View层级&#xff0c;但是通常在使用中 Activity即是View…

MVP框架模式

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

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

今天也是我学后端的朋友给我发了三个前端的面试题&#xff0c;这里我们试着分析一波。 目录 1、和的含义是什么&#xff0c;又有什么区别呢&#xff1f; &#xff08;1&#xff09;赋值&#xff1a; &#xff08;2&#xff09;相同&#xff1a; &#xff08;3&#xff09;…

前端面经总结

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

前端深入学习

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

web前端常用词汇

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

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

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