一. 前言

1. 介绍

MVP全名是Model-View-Presenter,MVP 是从经典的模式MVC演变而来的。

  • Model:模型层,负责处理数据的加载或存储。与MVP中的M一样。
  • View:视图层,负责界面数据的展示,与用户进行交互。与MVP中的V一样。
  • Presenter:负责逻辑业务的处理。跟MVC中的C有所区别。

2. 作用

  • 将Model与View彻底分离。
  • 解决MVC中Activity职责过多,代码臃肿的问题。

3. 流程

  • View接受用户的请求,然后将请求传递给Presenter。
  • Presenter进行业务逻辑处理,修改Model。
  • Presenter通知View去更新界面显示。

二. MVP实例

还是以点击按钮对数字+1为例子,将其改造成MVP模式。与MVC不同的是,一般Activty会当作View层来处理。

1. Model层处理

跟MVC不同的地方在于Model不会跟View发生交互,只会跟Presenter交互。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class NumModel {
private int num = 0;

public void add(ModelCallback callback){
callback.onSuccess(++num);
}

/**
* 数据回调接口
*/
public interface ModelCallback {
void onSuccess(int num);
void onFailed(int num);
}
}

2. View层

MVP中Activty也充当了View层,同时会持有Presenter的引用。

IView接口,暴露给Presenter的方法:

1
2
3
public interface IView {
void updateUI(String text);
}

PresenterActivity类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class PresenterActivity extends AppCompatActivity implements IView {

private TextView textView;
private Button button;
private NumModel numModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

textView = findViewById(R.id.tv_show);
button = findViewById(R.id.btn_add);

final NumPresenter numPresenter = new NumPresenter(this);

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//交给Present去处理
numPresenter.add();
}
});
}

//更新UI
@Override
public void updateUI(String text) {
textView.setText(text);
}
}

3. Presenter层

负责业务逻辑处理。

IPresent接口,暴露给View调用:

1
2
3
public interface IPresent {
void add();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class NumPresenter implements NumModel.ModelCallback,IPresent {
private NumModel numModel;
private IView iView;

public NumPresenter(IView iView) {
//持有IView对象
this.iView = iView;

//初始化NumModel对象
numModel = new NumModel();
}

//ModelCallback成功回调的接口
@Override
public void onSuccess(int num) {
iView.updateUI(num + "");
}

//ModelCallback失败回调的接口
@Override
public void onFailed(int num) {
iView.updateUI("");
}

//IPresent接口的方法,来自View层的调用
@Override
public void add() {
numModel.add(this);
}
}

4. 运行结果

5. 源码

MVPTest

三. MVC与MVP的区别

最主要的区别就是MVP中View与Model并不直接交互,而在MVC中View可以与Model直接交互。

四. MVC的优缺点

1. 优点

  • View与Model完全分离,我们可以修改视图而不影响模型。

  • 可以更高效地使用模型,因为所有的交互都发生Presenter中。

  • Presenter与View的交互是通过接口来进行的,有利于添加单元测试。

2. 缺点

  • 页面逻辑复杂的话,相应的接口也会变多,增加维护成本。可以定义一些基类去分离一些公共的逻辑。

  • 系统内存不足时,系统会回收Activity。一般我们都是用OnSaveInstanceState()去保存状态,用OnRestoreInstanceState()去恢复状态。但是在我们的MVP中,View层是不应该去直接操作Model的,所以这样做不合理,同时也增大了M与V的耦合。解决办法是不要将Activity作为View层,可以把Activity当Presenter来处理。具体实现这里就不分析了,有兴趣的可以研究一下。

  • UI改变的话,比如TextView 替换 EditText,可能导致Presente的一些更新UI的接口也跟着需要更改,存在一定的耦合。

参考文章

Android框架模式——MVP