关于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{ /** * @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 HashMapparamMap; public BaseBeanManager(ViewCallBack modelCallBack) { mViewCallBack = modelCallBack; } public abstract void getData();}复制代码
- V层封装
public abstract class BaseActivityextends AppCompatActivity implements ViewCallBack { 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 HashMapparamMap = 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 BaseActivityimplements ViewCallBack { 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转换过来的时候很不习惯,后来折腾了一阵子,发现其实挺好用的。