关于MVP分层架构在项目中的实际运用

关于MVP的基本知识网上已经有很多了,但是很多都只是Demo,毕竟Demo跟实际运用之间还有无数个Debug,其实一开始我也看了很多关于MVP的介绍,其中有谷歌官方的Demo,还有很多技术博客,那个时候就觉得自己知道什么是MVP了,后来真正在自己项目中运用的时候,才发现并不是那么简单,不过经过一番折腾,逐渐对MVP有了比较深层次的认识,所以今天记录分享一下。

MVP结构示意图

我自己画了一个关系图,也就是最简单的MVP结构示意图,我在这里并不会再解释什么是MVP,今天我想把所有的认知转化为代码,也就是图中的关系图,他们之间的关系我全部都是用Callback来进行联系的,也就是之前说的引用。

M层

  • 这里的M层不是传统意义上的Model,我更倾向于认为他是一个ModelManager,就是一个数据处理中心,可以处理网络数据,数据库,文件以及关于Android中的四大组件的交互包含BroadcastReceiver,Service中的,都可以集中在这里面处理,有很长一段时间对于M的认知都是觉得就是个实体类,那个时候还以为自己掌握地很透彻,最后发现自己理解的其实是不对的,MddelManager持有Presenter的引用,M处理完数据之后通过Callback回调Presenter,Presenter由于持有View的引用,所以可以回调View

V层

  • V就是指View(界面),往大了说是Activity或者Fragemnt,往小了说可以是一个Dialog、Toast或者Snakbar,具体就是直接跟用户进行打交道的,View会实现Callback接口,然后传递给Presenter,然后Presenter会去ModelManager进行交互,然后数据处理完成之后,会通过Callback回调回来,这样就完成了一个闭环

P层

  • P就是Presenter,主持人其实挺形象的,就起一个客串的作用,相当于一座桥,来连接Vie跟ModelManger,很多文章是把逻辑在Presenter中进行处理的,我觉得不是很好,我认为在Modelmanager里面处理比较好,这样解耦的更彻底,毕竟Presenter只是个中间的信使而已,不应该处理过多的逻辑。

关系搞清楚了,其实代码实现就比较简单

M层代码

1
2
3
4
5
6
7
8
9
10
11
public class MainManager {
private ViewCallBack mViewCallBack;

public MainManager(ViewCallBack viewCallBack) {
this.mViewCallBack = viewCallBack;
}

public void getData() {
mViewCallBack.refreshView(1, "数据");
}
}

这里面只是写了一个模板,可能一个界面需要多种数据处理方式,那么就根据需求在重新定义几个方法即可

V层代码

1
2
3
4
5
6
7
8
9
public interface ViewCallBack<V> {

/**
* @param code code:0:有数据,1:数据为空,2:加载失败
* @param data 定义好的数据类型
*/

void refreshView(int code, V data);
}

这里的V采取泛型的原因在于每个界面需要获取的数据不一样,所以用泛型加以区分,当一个界面需要获取的接口很多,或者得到的数据结果类型不太一致的时候,这里的泛型就需要用Object来指定,然后在refreshView中通过数据的类型来判断需要刷新的数据

P层代码

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MainPresenter {
private ViewCallBack mViewCallBack;
private MainManager mMainManager;

public MainPresenter(ViewCallBack viewCallBack) {
this.mViewCallBack = viewCallBack;
mMainManager = new MainManager(mViewCallBack);
}

public void getData() {
mMainManager.getData();
}
}

P层代码的方法跟Manager对应,然后处理M层跟V层的Callback即可,但是注意Presenter是一个对象,需要在界面销毁的时候置空,防止内存泄露

我在demo中只是简单写了一个改变Text的值,当然在Manager里面可以进行任何你想要的操作,因为是采用接口回调,运行一下看看效果

MVP效果图

持续封装

上面的只是一个Demo,下面进行封装抽取,方便集成到真正的项目中去

  1. M层封装
1
2
3
4
5
6
7
8
9
10
public abstract class BaseBeanManager {

protected ViewCallBack mViewCallBack;
protected HashMap<String, String> paramMap;

public BaseBeanManager(ViewCallBack modelCallBack) {
mViewCallBack = modelCallBack;
}
public abstract void getData();
}
  1. V层封装
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
32
33
34
35
36
37
38
39
40
41
 public abstract class BaseActivity<T extends BasePresenter, V> extends AppCompatActivity implements ViewCallBack<V> {
public T presenter;//泛型定义Presenter
@TargetApi(Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(getLayoutId());
presenter = initPresenter();
initViews();
initListener();
}

@Override
protected void onResume() {
super.onResume();
//初始化Presenter
if (presenter == null)
presenter = initPresenter();
//添加Callback
presenter.add((ViewCallBack) this);

}
protected abstract int getLayoutId();

protected abstract void initViews();

protected abstract void initListener();//初始化监听事件

protected abstract T initPresenter();//初始化Presenter

@Override
protected void onDestroy() {
super.onDestroy();
//生命周期结束时销毁callback,并置空presenter
if (presenter != null){
presenter.remove();
presenter = null;

}
}
}
  1. P层封装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class BasePresenter {
protected BaseBeanManager mBeanManager;//定义基类manager
protected HashMap<String, String> paramMap = new HashMap<>();
protected ViewCallBack mViewCallBack;

public BasePresenter(ViewCallBack viewCallBack) {
mViewCallBack = viewCallBack;
}


public void add(ViewCallBack viewCallBack) {
this.mViewCallBack = viewCallBack;
}

public void remove() {
this.mViewCallBack = null;
}
//默认的获取数据的方法
protected abstract void getData();


}

使用

  1. M层
1
2
3
4
5
6
7
8
9
10
public class MainManager extends BaseBeanManager {

public MainManager(ViewCallBack modelCallBack) {
super(modelCallBack);
}

public void getData() {
mViewCallBack.refreshView(1, "MVP返回的数据");
}
}

2.V层

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
32
33
34
public class MainActivity extends BaseActivity<MainPresenter, String> implements ViewCallBack<String> {
private TextView tvDemo;
private Button btnGet;
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}

@Override
protected void initViews() {
tvDemo = (TextView) findViewById(R.id.tv_demo);
btnGet = (Button) findViewById(R.id.btn_get);
}

public void initListener() {
btnGet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.getData();
}
});
}

@Override
protected MainPresenter initPresenter() {
return new MainPresenter(this);
}

@Override
public void refreshView(int code, String data) {
tvDemo.setText(data);
}

}
  1. P层
1
2
3
4
5
6
7
8
9
10
11
12
public class MainPresenter extends BasePresenter {

public MainPresenter(ViewCallBack viewCallBack) {
super(viewCallBack);
}


public void getData() {
mBeanManager = new MainManager(mViewCallBack);
mBeanManager.getData();
}
}

本身是不想贴这么多代码的,但是只有对比才能发现,MVP由于解耦地比较彻底,所以满足单一职责原则,新增了很多类,封装之后,即使新建的类变多了,每个类都需要一个相应的Presenter,但是代码量很少,所以看起来逻辑比较清楚

这就是我的项目中正在使用的的MVP,刚开始从MVC转换过来的时候很不习惯,后来折腾了一阵子,发现其实挺好用的。

项目下载地址