前言:
本篇关于MVP架构的学习是在查阅了很多资料整理出来。网上一些关于Android MVP的介绍都有点浅尝辄止,一个登录或者根据地区查询天气等的小Demo,没有实际在项目中应用的示例,所以在用MVP做完一个小项目之后还是不敢在主项目中轻易尝试。首先,主项目改动起来工作量很大,时间不允许;其次,知道自身对MVP理解还不够,怕掉坑里去;今天主要是想分享一下,本人对MVP的浅见,以及如何使用MVP模式搭建一个项目框架。后续在工作中学习到了有关于MVP模式的见解会继续发表文章。
微软公司对MVC和MVP模式的差异图解:
我们模拟一个需求:首先我们要进入一个Splash界面,Splash界面中,有一个ProgressBar控件和TextView控件,我们判断它是否有网络连接,如果有的话就隐藏 ProgressBar和跳转到MainActivity如果没有网络的话则显示ProgressBar和TextView,TextView则提示用户No internet。就这么简单的一个需求,我们看看如何用MVP模式做这个需求。
首先我们看下M层是如何接口写的
优点:
1. 降低耦合度,实现了Model和View真正的完全分离,可以修改View而不影响Modle
2. 模块职责划分明显,层次清晰(下面会介绍Bob大叔的Clean Architecture)
3. 隐藏数据
4. Presenter可以复用,一个Presenter可以用于多个View,而不需要更改Presenter的逻辑(当然是在View的改动不影响业务逻辑的前提下)
5. 利于测试驱动开发。以前的Android开发是难以进行单元测试的(虽然很多Android开发者都没有写过测试用例,但是随着项目变得越来越复杂,没有测试是很难保证软件质量的;而且近几年来Android上的测试框架已经有了长足的发展——开始写测试用例吧),在使用MVP的项目中Presenter对View是通过接口进行,在对Presenter进行不依赖UI环境的单元测试的时候。可以通过Mock一个View对象,这个对象只需要实现了View的接口即可。然后依赖注入到Presenter中,单元测试的时候就可以完整的测试Presenter应用逻辑的正确性。
6. View可以进行组件化。在MVP当中,View不依赖Model。这样就可以让View从特定的业务场景中脱离出来,可以说View可以做到对业务完全无知。它只需要提供一系列接口提供给上层操作。这样就可以做到高度可复用的View组件。
7. 代码灵活性
缺点:
1. Presenter中除了应用逻辑以外,还有大量的View->Model,Model->View的手动同步逻辑,造成Presenter比较笨重,维护起来会比较困难。
2. 由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。
3. 如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。
4. 额外的代码复杂度及学习成本。
什么是MVP
MVP,全称 Model-View-Presenter
要说MVP那就不得不说一说它的前辈——MVC。
MVC(Model-View-Controller,模型-视图-控制器)模式是80年代Smalltalk-80出现的一种软件设计模式,后来得到了广泛的应用,其主要目的在于促进应用中模型,视图,控制器间的关注的清晰分离。MVP(Model-View-Presenter,模型-视图-表示器)模式则是由IBM开发出来的一个针对C++和Java的编程模型,大概出现于2000年,是MVC模式的一个变种,主要用来隔离UI、UI逻辑和业务逻辑、数据。也就是说,MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方: Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示(一般可以理解为Activity和Fragment)。
要说MVP那就不得不说一说它的前辈——MVC。
MVC(Model-View-Controller,模型-视图-控制器)模式是80年代Smalltalk-80出现的一种软件设计模式,后来得到了广泛的应用,其主要目的在于促进应用中模型,视图,控制器间的关注的清晰分离。MVP(Model-View-Presenter,模型-视图-表示器)模式则是由IBM开发出来的一个针对C++和Java的编程模型,大概出现于2000年,是MVC模式的一个变种,主要用来隔离UI、UI逻辑和业务逻辑、数据。也就是说,MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方: Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示(一般可以理解为Activity和Fragment)。
微软公司对MVC和MVP模式的差异图解:
大家会发现MVP与MVC最大的一个区别就是“Model与View层之间倒底该不该通信(甚至双向通信)。我想这也是目前做这两方面研究的专家所互相争论的战场。必定各有各的好处和因好处要付出的代价。起码在MVP模式下的Presenter要拥有“绝对权力”。如果没有它,MODEL与View就是两个孤岛,尽管各有各的地盘(完全解耦),但不会给企业带来什么有用的价值。
MVP案例分析:
这篇博客
MVP模式在Android开发中的应用 的案例也很好理解,AndroidStudio版源码下载:
源码。只是有一个问题,这样会造成内存泄漏。优化后代码下载:待续。。。
下面再举一个例子:
待续。。。
一个MVP的项目,先从项目目录结构上面来看
首先我们看下M层是如何接口写的
package com.manning.androidhacks.hack020.presenter.model;
public interface IConnectionStatus {
boolean isOnline();
}
然后看看实现(我们主要是看MVP模式的使用,所以在此就不做网络连接的检查了,模拟一个状态)
package com.manning.androidhacks.hack020.presenter.model.impl;
import com.manning.androidhacks.hack020.presenter.model.IConnectionStatus;
public class ConnectionStatus implements IConnectionStatus {
@Override
public boolean isOnline() {
// TODO: Here we should place the code to check the connectivity.
return true;
}
}
然后我们在来看看V的接口
package com.manning.androidhacks.hack020.view;
public interface ISplashView {
void showProgress();
void hideProgress();
void showNoInetErrorMsg();
void moveToMainView();
}
以及V的实现
package com.manning.androidhacks.hack020.view.impl;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.manning.androidhacks.hack020.R;
import com.manning.androidhacks.hack020.presenter.SplashPresenter;
import com.manning.androidhacks.hack020.view.ISplashView;
public class SplashActivity extends Activity implements ISplashView {
private TextView mTextView;
private ProgressBar mProgressBar;
private SplashPresenter mPresenter = new SplashPresenter();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
mPresenter.setView(this);
mTextView = (TextView) findViewById(R.id.splash_text);
mProgressBar = (ProgressBar) findViewById(R.id.splash_progress_bar);
}
@Override
protected void onResume() {
super.onResume();
mPresenter.didFinishLoading();
}
public void showProgress() {
mProgressBar.setVisibility(View.VISIBLE);
}
public void hideProgress() {
mProgressBar.setVisibility(View.INVISIBLE);
}
public void showNoInetErrorMsg() {
mTextView.setText("No internet");
}
@Override
public void moveToMainView() {
startActivity(new Intent(this, MainActivity.class));
}
}
最后我们来看看P层是如何控制他们的逻辑的:
public class SplashPresenter {
private IConnectionStatus mConnectionStatus;
private ISplashView mView;
public SplashPresenter() {
this(new ConnectionStatus());
}
public SplashPresenter(IConnectionStatus connectionStatus) {
mConnectionStatus = connectionStatus;
}
public void setView(ISplashView view) {
this.mView = view;
}
protected ISplashView getView() {
return mView;
}
public void didFinishLoading() {
ISplashView view = getView();
if (mConnectionStatus.isOnline()) {
view.showProgress();
view.moveToMainView();
} else {
view.hideProgress();
view.showNoInetErrorMsg();
}
}
}
MVP 的优缺点:
任何事务都存在两面性,MVP当然也不列外,我们来看看MVP的优缺点。优点:
1. 降低耦合度,实现了Model和View真正的完全分离,可以修改View而不影响Modle
2. 模块职责划分明显,层次清晰(下面会介绍Bob大叔的Clean Architecture)
3. 隐藏数据
4. Presenter可以复用,一个Presenter可以用于多个View,而不需要更改Presenter的逻辑(当然是在View的改动不影响业务逻辑的前提下)
5. 利于测试驱动开发。以前的Android开发是难以进行单元测试的(虽然很多Android开发者都没有写过测试用例,但是随着项目变得越来越复杂,没有测试是很难保证软件质量的;而且近几年来Android上的测试框架已经有了长足的发展——开始写测试用例吧),在使用MVP的项目中Presenter对View是通过接口进行,在对Presenter进行不依赖UI环境的单元测试的时候。可以通过Mock一个View对象,这个对象只需要实现了View的接口即可。然后依赖注入到Presenter中,单元测试的时候就可以完整的测试Presenter应用逻辑的正确性。
6. View可以进行组件化。在MVP当中,View不依赖Model。这样就可以让View从特定的业务场景中脱离出来,可以说View可以做到对业务完全无知。它只需要提供一系列接口提供给上层操作。这样就可以做到高度可复用的View组件。
7. 代码灵活性
缺点:
1. Presenter中除了应用逻辑以外,还有大量的View->Model,Model->View的手动同步逻辑,造成Presenter比较笨重,维护起来会比较困难。
2. 由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。
3. 如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。
4. 额外的代码复杂度及学习成本。
参考资料:
MVP google官方demo比较分析:
http://www.jianshu.com/p/14283d8d3a60
开源项目Philm的MVP架构分析:
http://www.devtf.cn/?p=650
Android mvp 架构的自述:
http://blog.csdn.net/dantestones/article/details/50899235