Android MVP 模式使用指南
参考github代码:github
参考博客:Google 官方Android MVP架构实践
简单的以google官方代码和自己的demo记录Android的MVP设计模式。
1.官方MVP模式:
官方MVP的samples的github地址是(https://github.com/googlesamples/android-architecture/)
若水三千,我们先取一瓢。先看看最简单的todo-mvp分支,这是最基础的MVP架构samples。
在我从前认识的MVP模式中,并不存在BasePresenter和BaseView两个文件,只需要针对不同的Presenter和View来定义不同的接口就行了。
来看一下这两个文件中都写了啥:
BasePresenter.java
public interface BasePresenter {void start();
}BaseView.java
public interface BaseView<T> {void setPresenter(T presenter);
}
BasePresenter中声明了一个方法,当我们的实现类presenter需要开始进行动作时,事先调用start方法,来进行一些预处理动作。(代码中都是在View的实现类的onResume中调用presenter的start方法)。
因为google的sample中presenter需要做一些画面初始化的操作,所以每个画面都需要这样的方法将数据加载到画面上,所以使用了这个方法来作为初始化方法,我们在实际编码时要根据情况观察是否使用这个模板。
BaseView中声明了一个方法,setPresenter(),这里的设计和我平常的理解有所不同。我平时的想法是在view的onCreate方法中new出presenter实例作为view的成员变量,而google的例子是在activity中使用fragment实例new出presenter实例,但是这个presenter不属于fragment,需要在presenter中调用mTasksView.setPresenter(this)。
TasksActivity.java
@Overrideprotected void onCreate(Bundle savedInstanceState) {...TasksFragment tasksFragment =(TasksFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);...// Create the presentermTasksPresenter = new TasksPresenter(Injection.provideTasksRepository(getApplicationContext()), tasksFragment);...}
TasksPresenter.java
public TasksPresenter(@NonNull TasksRepository tasksRepository, @NonNull TasksContract.View tasksView) {mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null");mTasksView = checkNotNull(tasksView, "tasksView cannot be null!");mTasksView.setPresenter(this);}
另外,我们发现google提供的包结构与我常用的不同,我们会按照模块来进行划分,例如:view,presenter,util,contract。但是google是将view,presenter,contract放在一起的,仁者见仁吧。
2.我认识的MVP模式:
首先我们会定义一个接口叫做Contract,在其中我们会定义三个接口,分别是Presenter,View和Model的接口,其中View和Model中都只声明了一个方法供presenter调用,而Presenter中声明了两个方法供View和Model调用。
当然,一般在一个app中不可能只有一个Contract,因为我们需要针对不同类型的画面定义不同的画面方法,每个不同类型的画面上的逻辑也不会相同。
接下来我们来说明一下一个正常的mvp模式是如何运作的,我们需要实现一个很简单的功能,登录检查。
(检查用户名和密码是否与我们数据库中的匹配,这里为了简单起见,我们就不再写数据库的操作了,而是直接使用现成的字符串来检查)。
首先,这是我们的Contract部分,因为我们只需要针对一个登录画面,所以我们只需要一个Contract来存放三个接口。
/*** This specifies the contract between the view and the presenter.*/
public interface LoginContract {interface Presenter {/*** login action.* @param name user name.* @param pwd user password.*/void login(String name, String pwd);/*** set login result for presenter instance.* @param resultCode*/void setLoginResult(int resultCode);}interface View {/*** show login result for view instance.* @param resultCode login result;* {@link LoginPresenter#LOGIN_ERROR}, {@link LoginPresenter#LOGIN_SUCCESS}.*/void showLoginResult(int resultCode);}interface Model {/*** login action.* @param name user name.* @param pwd user password.*/void login(String name, String pwd);}
}
接下来使我们的presenter的具体实现类,login方法只是向下调用了model的login方法,有人会觉得这样做很奇怪,不是多此一举吗?其实,Presenter的作用就是一个桥梁,连接View和Presenter的桥梁。
/*** Listens to user actions from the UI ({@link com.siw.mvp.view.MainActivity}), retrieves the data and updates the* UI as required.*/
public class LoginPresenter implements LoginContract.Presenter {private final static String TAG = LoginPresenter.class.getSimpleName();private LoginContract.View mView;private LoginContract.Model mModel;public static final int LOGIN_ERROR = 0;public static final int LOGIN_SUCCESS = 1;public LoginPresenter(LoginContract.View view) {this.mView = view;mModel = new LoginModel(this);}@Overridepublic void login(String name, String pwd) {Log.d(TAG, "login() enter, name = " + name + "pwd = " + pwd);mModel.login(name, pwd);}@Overridepublic void setLoginResult(int resultCode) {Log.d(TAG, "setLoginResult() enter, resultCode = " + resultCode);if (null != mView) {mView.showLoginResult(resultCode);} else {Log.e(TAG, "mView = null");}}
}
最后是Model,这里定义了其实现的接口中的方法,为了方便起见,在Model中的login逻辑处理只用了最简单的字符串比较。
public class LoginModel implements LoginContract.Model {private final static String TAG = LoginModel.class.getSimpleName();private LoginContract.Presenter mPresenter;public LoginModel(LoginContract.Presenter mPresenter) {this.mPresenter = mPresenter;}@Overridepublic void login(String name, String pwd) {Log.d(TAG, "login() enter");if (null == mPresenter) {Log.e(TAG, "mPresenter = null");return;}if ("admin".equals(name) && "root".equals(pwd)) {mPresenter.setLoginResult(LoginPresenter.LOGIN_SUCCESS);} else {mPresenter.setLoginResult(LoginPresenter.LOGIN_ERROR);}}
}
最后聊一聊一个问题,为什么要使用MVP模式,或者说,这种模式的好处在哪?
通过以上两个sample的分析,我们发现,使用MVP模式后,原本会被放在Activity或Fragment中的代码都被抽象出来了,被分成了MVP三个部分。这三个部分其实承担了三个不同的职责,View负责显示以及响应用户操作,Model负责处理逻辑,而Presenter则负责将View和Presenter两层联系起来,就像是一座桥。这样的三个部分的划分,极大的降低了代码之间的耦合度,让代码的执行变得十分清晰明确。
另外,有人想问,中间的Presenter层的作用是什么呢?Presenter的存在进一步分离了上层画面和底层逻辑,在Android中,我们的底层逻辑会更多的使用异步线程的方式执行,那么Presenter就可以承担起一个业务逻辑层的作用,让Model层进行纯粹的底层逻辑的执行。
一般来说,MVP设计模式适合稍微大一些的项目,如果只是简单的小demo,那么没有必要使用MVP。
Android MVP 模式使用指南相关推荐
- Android MVP模式 简单易懂的介绍方式
主要学习这位大神的博客:简而易懂 Android MVP模式 简单易懂的介绍方式 https://segmentfault.com/a/1190000003927200 转载于:https://www ...
- Android MVP模式简单易懂的介绍方式 (一)
Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式 ...
- android mvp模式例子_ANDROID MVP 模式 简单易懂的介绍方式
Android MVP Pattern Android MVP 模式1 也不是什么新鲜的东西了,我在自己的项目里也普遍地使用了这个设计模式.当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP ...
- Android MVP模式 解析JSON 显示到ListView上
Android MVP模式 解析JSON 显示到ListView上 有关MVP模式的介绍,这里不作详细解释,稍后会更新MVP设计模式,请等待链接-- 简述本次的主要功能实现: 通过mvp设计模式,(M ...
- android mvp 利弊,android mvp模式有什么弊端 - 什么是android mvp模式,android mvp模式有什么弊端...
android mvp模式有什么弊端 才开始学习使用MVP时,看到大家说了很多MVP的优点,代码复用,条理清晰等等.不过我改下来发现,MVP在我看来,最大的优点还是代码解耦,逻辑清晰,至于代码复用,暂 ...
- Android MVP模式学习
Android MVP模式学习 参考: Android MVP 开发模式有哪些优缺点?: https://www.zhihu.com/question/35185744 MVP 模式简单易懂的介绍方式 ...
- Android MVP模式就是这么回事儿
MVP模式 概念就不说了,大家都懂.View层通过Persenter层相互通信,避免了View中大量的业务代码,而将其提取到Model中.其实简单的来说,就是通过接口回调,把业务分离出去.提高代码的可 ...
- android mvp模式
越来越多人讨论mvp模式,mvp在android应用开发中获得更多的重视,这里说一下对MVP的简单了解. 什么是 MVP? MVP模式使逻辑从视图层分开,目的是我们在屏幕上怎么表现,和界面如何工作的所 ...
- Xamarin.Android MVP模式
一.简介 随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数 据的可视化以及与用户的交互,同时让Model只 ...
最新文章
- 合肥工业大学—SQL Server数据库实验八:使用聚集函数的SELECT语句
- C++实现求字符串的所有的组合
- JS事件流和事件委托
- Network 【TCP/IP 四层模型】
- java break在switch_java中switch case语句需要加入break的原因解析
- html的li浮动之后往下移动,多个li浮动后居中显示问题
- 为什么一次ajax调用会发送两次请求?
- 日志规范之slf4j整合JDK14以及Simple的使用
- 苹果和虫子问题C++
- 用gensim doc2vec计算文本相似度,Python可以跑通的代码
- 西安计算机二级12月,2017年12月计算机二级MS Office习题答案(一)
- HDU3571 N-dimensional Sphere(高斯消元 同模方程)
- 【语音去噪】基于matlab GUI LMS+RLS语音去噪【含Matlab源码 528期】
- 【CSS笔记】CSS实现后台管理系统主界面布局
- pixel 刷入自己编译的Android 8.0 安装Xposed 显示 Verified Boot (dm-verity) prevents the device from booting
- pr预设导入安装教程,prfpset文件怎么导入pr?
- html5笔迹画图,html5绘图工具canvas模拟笔迹绘画特效
- 【综述】3D智能数字化与3D打印:中国制造向中国智造转变的机遇
- 导数在梯度下降算法中的意义理解
- 牛!虚拟化SIG最新技术成果受国际媒体报道!