关于MVP的基本知识网上已经有很多了,但是很多都只是Demo,毕竟Demo跟实际运用之间还有无数个Debug,其实一开始我也看了很多关于MVP的介绍,其中有谷歌官方的Demo,还有很多技术博客,那个时候就觉得自己知道什么是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层代码
public class MainManager {
private ViewCallBack mViewCallBack;
public MainManager(ViewCallBack viewCallBack) {
this.mViewCallBack = viewCallBack;
}
public void getData() {
mViewCallBack.refreshView(1, "数据");
}
}
这里面只是写了一个模板,可能一个界面需要多种数据处理方式,那么就根据需求在重新定义几个方法即可
V层代码
public interface ViewCallBack<V> {
/**
* @param code code:0:有数据,1:数据为空,2:加载失败
* @param data 定义好的数据类型
*/
void refreshView(int code, V data);
}
这里的V采取泛型的原因在于每个界面需要获取的数据不一样,所以用泛型加以区分,当一个界面需要获取的接口很多,或者得到的数据结果类型不太一致的时候,这里的泛型就需要用Object来指定,然后在refreshView中通过数据的类型来判断需要刷新的数据
P层代码
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里面可以进行任何你想要的操作,因为是采用接口回调,运行一下看看效果
持续封装
上面的只是一个Demo,下面进行封装抽取,方便集成到真正的项目中去
- M层封装
public abstract class BaseBeanManager {
protected ViewCallBack mViewCallBack;
protected HashMap<String, String> paramMap;
public BaseBeanManager(ViewCallBack modelCallBack) {
mViewCallBack = modelCallBack;
}
public abstract void getData();
}
- V层封装
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;
}
}
}
- P层封装
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();
}
使用
- M层
public class MainManager extends BaseBeanManager {
public MainManager(ViewCallBack modelCallBack) {
super(modelCallBack);
}
public void getData() {
mViewCallBack.refreshView(1, "MVP返回的数据");
}
}
2.V层
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);
}
}
- P层
public class MainPresenter extends BasePresenter {
public MainPresenter(ViewCallBack viewCallBack) {
super(viewCallBack);
}
public void getData() {
mBeanManager = new MainManager(mViewCallBack);
mBeanManager.getData();
}
}
本身是不想贴这么多代码的,但是只有对比才能发现,MVP由于解耦地比较彻底,所以满足单一职责原则,新增了很多类,封装之后,即使新建的类变多了,每个类都需要一个相应的Presenter,但是代码量很少,所以看起来逻辑比较清楚
这就是我的项目中正在使用的的MVP,刚开始从MVC转换过来的时候很不习惯,后来折腾了一阵子,发现其实挺好用的。