参考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 模式使用指南相关推荐

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

    主要学习这位大神的博客:简而易懂 Android MVP模式 简单易懂的介绍方式 https://segmentfault.com/a/1190000003927200 转载于:https://www ...

  2. Android MVP模式简单易懂的介绍方式 (一)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式 ...

  3. android mvp模式例子_ANDROID MVP 模式 简单易懂的介绍方式

    Android MVP Pattern Android MVP 模式1 也不是什么新鲜的东西了,我在自己的项目里也普遍地使用了这个设计模式.当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP ...

  4. Android MVP模式 解析JSON 显示到ListView上

    Android MVP模式 解析JSON 显示到ListView上 有关MVP模式的介绍,这里不作详细解释,稍后会更新MVP设计模式,请等待链接-- 简述本次的主要功能实现: 通过mvp设计模式,(M ...

  5. android mvp 利弊,android mvp模式有什么弊端 - 什么是android mvp模式,android mvp模式有什么弊端...

    android mvp模式有什么弊端 才开始学习使用MVP时,看到大家说了很多MVP的优点,代码复用,条理清晰等等.不过我改下来发现,MVP在我看来,最大的优点还是代码解耦,逻辑清晰,至于代码复用,暂 ...

  6. Android MVP模式学习

    Android MVP模式学习 参考: Android MVP 开发模式有哪些优缺点?: https://www.zhihu.com/question/35185744 MVP 模式简单易懂的介绍方式 ...

  7. Android MVP模式就是这么回事儿

    MVP模式 概念就不说了,大家都懂.View层通过Persenter层相互通信,避免了View中大量的业务代码,而将其提取到Model中.其实简单的来说,就是通过接口回调,把业务分离出去.提高代码的可 ...

  8. android mvp模式

    越来越多人讨论mvp模式,mvp在android应用开发中获得更多的重视,这里说一下对MVP的简单了解. 什么是 MVP? MVP模式使逻辑从视图层分开,目的是我们在屏幕上怎么表现,和界面如何工作的所 ...

  9. Xamarin.Android MVP模式

    一.简介 随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数 据的可视化以及与用户的交互,同时让Model只 ...

最新文章

  1. 合肥工业大学—SQL Server数据库实验八:使用聚集函数的SELECT语句
  2. C++实现求字符串的所有的组合
  3. JS事件流和事件委托
  4. Network 【TCP/IP 四层模型】
  5. java break在switch_java中switch case语句需要加入break的原因解析
  6. html的li浮动之后往下移动,多个li浮动后居中显示问题
  7. 为什么一次ajax调用会发送两次请求?
  8. 日志规范之slf4j整合JDK14以及Simple的使用
  9. 苹果和虫子问题C++
  10. 用gensim doc2vec计算文本相似度,Python可以跑通的代码
  11. 西安计算机二级12月,2017年12月计算机二级MS Office习题答案(一)
  12. HDU3571 N-dimensional Sphere(高斯消元 同模方程)
  13. 【语音去噪】基于matlab GUI LMS+RLS语音去噪【含Matlab源码 528期】
  14. 【CSS笔记】CSS实现后台管理系统主界面布局
  15. pixel 刷入自己编译的Android 8.0 安装Xposed 显示 Verified Boot (dm-verity) prevents the device from booting
  16. pr预设导入安装教程,prfpset文件怎么导入pr?
  17. html5笔迹画图,html5绘图工具canvas模拟笔迹绘画特效
  18. 【综述】3D智能数字化与3D打印:中国制造向中国智造转变的机遇
  19. 导数在梯度下降算法中的意义理解
  20. 牛!虚拟化SIG最新技术成果受国际媒体报道!

热门文章

  1. 七个简单方法就能增强你的免疫力
  2. 浏览器是如何工作的 - How Browser works
  3. 对node工程进行压力测试与性能分析
  4. 济南公交车辆实时定位手机web版
  5. 看了Python在金融行业中的应用,大数据分析实在太重要了
  6. 玉米社:视频播放量几十?是否作品出现了违禁词,怎么解决?
  7. 单片机程序应用、驱动分层独立开发方案
  8. 在java体系结构中集成Macromedia Flex(翻译)
  9. 应届生学C好还是学JAVA好,做什么更挣钱
  10. 用c语言画一个*组成的梯形