接触Android MVP模式在好早之前,一直也没有在项目中真正的实用。刚好有一个机会需要自己去做项目,然后就用上MVP。MVP用起来还是很方便,整个项目结构非常清晰,相比于传统的MVC模式,MVP清晰分工,有太多有点了。这些其实是需要在实用以后才能体会到的,尤其是当项目很复杂的时候。
一、MVP介绍
在MVP模式里通常包含4个要素:
- View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);
- View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;
- Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);
- Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。
二、为什么使用MVP模式
在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它 的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的 职责不断增加,以致变得庞大臃肿。当我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中 View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由 Presenter处理).
另外,回想一下你在开发Android应用时是如何对代码逻辑进行单元测试的?是否每次都要将应用部署到Android模拟器或真机上,然后通过模拟用 户操作进行测试?然而由于Android平台的特性,每次部署都耗费了大量的时间,这直接导致开发效率的降低。而在MVP模式中,处理复杂逻辑的 Presenter是通过interface与View(Activity)进行交互的,这说明了什么?说明我们可以通过自定义类实现这个 interface来模拟Activity的行为对Presenter进行单元测试,省去了大量的部署及测试的时间。
三、MVP与MVC的异同
MVC模式与MVP模式都作为用来分离UI层与业务层的一种开发模式被应用了很多年。在我们选择一种开发模式时,首先需要了解一下这种模式的利弊:
无论MVC或是MVP模式都不可避免地存在一个弊端:
- 额外的代码复杂度及学习成本。(这就导致了这两种开发模式也许并不是很小型应用。)
但比起他们的优点,这点弊端基本可以忽略了:
- 降低耦合度
- 模块职责划分明显
- 利于测试驱动开发
- 代码复用
- 隐藏数据
- 代码灵活性
四、案例
这里用一个案例来详细介绍MVP的实用,当然这里做一个基类封装方便使用。
IPresenterView接口
/**
* @author ttarfall
* @date 2016-09-06 10:08
*/
public interface IPresenterView {
}
(当然这里用了一个空的接口,其实是可以在里边加一些通用的方法)
BasePresenter基类
/**
* 基础basePresenter,用于IView接口的传入,attach,dettach用于绑定与解绑IView,当Activity被销毁的时候,及时解绑IView防止内存溢出
* @author ttarfall
* @date 2016-09-06 10:02
*/
public abstract class BasePresenter<T extends IPresenterView> {
protected T paresenterView;
public void attach(T mView) {
this.paresenterView = mView;
}
public void dettach() {
paresenterView = null;
}
}
BaseMVPActivity基类
import android.os.Bundle;
/**
* @author ttarfall
* @date 2016-09-06 09:36
*/
public abstract class BaseMVPActivity<V extends IPresenterView, P extends BasePresenter<V>> extends BaseActivity {
protected P presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = initPresenter();
try {
presenter.attach((V) this);
} catch (Exception e){
new ClassCastException(this.toString() +"实现IPresenterView或者IPresenterView子类接口");
}
}
@Override
protected void onDestroy() {
presenter.dettach();
super.onDestroy();
}
//实例化Presenter
public abstract P initPresenter();
}
BaseMVPFragment基类
import android.os.Bundle;
/**
* @author ttarfall
* @date 2016-09-08 13:45
*/
public abstract class BaseMVPFragment<V extends IPresenterView, P extends BasePresenter<V>> extends BaseFragment {
protected P presenter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = initPresenter();
try {
presenter.attach((V) this);
} catch (Exception e) {
new ClassCastException(this.toString() + "实现IPresenterView或者IPresenterView子类接口");
}
}
@Override
public void onDestroy() {
presenter.dettach();
super.onDestroy();
}
//实例化Presenter
public abstract P initPresenter();
}
上边是MVP做了一个简单的封装,接下来就是使用了。如图
IMainView源码,当然这里的ILoaddingView 接口也是继承IPresenterView ,只不过增加了一个setLoading方法。
MainPresenter部分源码截图,可以看到我这里其实有3个mode,当然每一个mode都有自己实现的方法。
mode存主要是获取数据的和保存数据使用。这里展示UserInfoMode的使用,IUserInfoMode展示提供的方法。
最后就是IMainView需要在Activity或者Fragment中实现。然后就是Presenter通过IPresenter与Activity或者Fragment互动。
至此一整套MVP的解释到案例就结束了,如果还有不太懂得童鞋可以留言。