与孤独为伴,让自己来一场涅槃
项目GitHub地址:https://github.com/ms-liu/ProjectFrameDemo
一、了解
在传统的Android项目开发过程中,按照MVC模块划分的话,往往会发现其实并不能很好的划分出各自的职责出来,Activity有时既需要扮演C的角色还需要扮演V的角色。这就导致Activity中代码耦合现象严重,尤其对于某些业务逻辑相对复杂的页面,动不动就是上千行的代码。
可能对于这些页面一代开发人员来说还能很愉快的接受,但是当新人来维护时,这就会让他很头痛了;
“他在写些什么? (黑人问号 黑人问号)他应该是个大神,代码我都看不懂,我要好好研究研究!”
在这种现象的基础上,便有了MVP的开发模式:
- Model:数据层——业务逻辑和实体类
- View:视图层——页面展示
- Presenter:逻辑层——数据和视图层交互
单单从目前的分析来看,MVP和MVC并没有什么大的区别,当然这两者本身本质上的区别不大,都是用作解耦V和M,只是将MVC套到Android开发过程中的时候,让Activity等一些组件,角色扮演不是那么清晰,所以导致了问题产生。
而在MVP的模式中,将Activity这些组件完全当成View层,让Activity职责单一化。Presenter负责数据处理,然后通过接口的形式达到与View交互的目的。让View和Model不在有交集。

这篇文章不作MVP如何编写的讲解,如需了解可自行百度,另外项目里面也包含了MVP 编写代码。
二、提升与改进(重点与目的)
其实有过了解或者使用MVP的开发人员,应当都能体会感受到,MVP确实能够将Activity中代码简化。但是对于那些业务复杂界面,Presenter中代码也是会急剧增多,并且有时也会将View层中代码放到Presenter中,重新回到老状态。
另外不知道有没有人碰到和我一样的问题,就是在使用MVP的过程中,有时在打开多个Activity页面后,回退过程中,在某些使用Fragment的Activity中会报出NullPointException,这是因为在我们打开过多页面时,由于内存和生命周期管理导致Fragment被系统回收,但是我们并没有将这些告知Presenter,从而发生NullPointException。
下面我们就一起来解决,这些问题。
(一)框架分析

在该框架中,我们在V和P之间加上了一个Proxy或Controller代理类,我们将会尽量少的让P和V直接进行交互接触,而是通过Proxy与V进行交互,在Proxy中预先处理部分逻辑,从而达到减轻Presenter职责的目的,让Presenter中代码更加简洁,更加专注于业务处理逻辑。
(二)Code

1、Model层
- 定义IModel数据接口
public interface IModel<T> { void setModel(T t); T getModel(); } -
实现IModel接口
public class ImproveModelImpl implements IModel<ImproveInfoBean>{ private ImproveInfoBean mModel; @Override public void setModel(ImproveInfoBean improveInfoBean) { this.mModel = improveInfoBean; } @Override public ImproveInfoBean getModel() { if (this.mModel == null){ this.mModel = new ImproveInfoBean(); } return mModel; } }
2、View层代码
-
定义View生命周期监听接口
public interface OnViewStateListener { void onCreate(); void onPause(); void onResume(); void onStop(); void onDestroy(); } -
定义公共IView接口
public interface IView { // 绑定对View生命周期监听 void bindListener(OnViewStateListener listener); Context getContext(); // Toast提示 void showToast(String message); //显示加载对话框 void showLoadingDialog(String message); // 隐藏加载对话框 void hideLoadingDialog(); } -
编写ViewDelegate
对 View操作的委托类,实现IView和OnViewStateListener接口中的方法public class ViewDelegate implements IView,OnViewStateListener { private Context mCtx; private ProgressDialog mProgressDialog; public ViewDelegate(Context context){ this.mCtx = context; } private List<OnViewStateListener> mOnViewStateListeners ; @Override public void bindListener(OnViewStateListener listener) { //用数组管理每一个View的生命周期,避免一个页面有多个监听 if (mOnViewStateListeners == null){ mOnViewStateListeners = new ArrayList<>(); mOnViewStateListeners.add(listener); }else { if (!mOnViewStateListeners.contains(listener)){ mOnViewStateListeners.add(listener); } } } @Override public Context getContext() { return mCtx; } @Override public void showToast(String message) { if (mCtx != null) { Toast.makeText(mCtx, message, Toast.LENGTH_SHORT).show(); } } @Override public void showLoadingDialog(String message) { if (mCtx != null){ mProgressDialog = new ProgressDialog(mCtx); } } @Override public void hideLoadingDialog() { if (mProgressDialog != null && mProgressDialog.isShowing()){ mProgressDialog.hide(); } } //------------------View生命周期管理-------------------------------------------------------- @Override public void onCreate() { if (checkListener()){ for (OnViewStateListener listener: mOnViewStateListeners) { listener.onCreate(); } } } @Override public void onPause() { if (checkListener()){ for (OnViewStateListener listener: mOnViewStateListeners) { listener.onPause(); } } } @Override public void onResume() { if (checkListener()){ for (OnViewStateListener listener: mOnViewStateListeners) { listener.onResume(); } } } @Override public void onStop() { if (checkListener()){ for (OnViewStateListener listener: mOnViewStateListeners) { listener.onStop(); } } } @Override public void onDestroy() { if (checkListener()){ for (OnViewStateListener listener: mOnViewStateListeners) { listener.onDestroy(); } } } private boolean checkListener(){ return mOnViewStateListeners != null && !mOnViewStateListeners.isEmpty(); } } -
编写BaseActivity,在里面实现页面公共操作方法
public class BaseActivity extends AppCompatActivity implements IView{ private ViewDelegate mDelegate; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //可以考虑注解创建 mDelegate = new ViewDelegate(this); } @Override public void bindListener(OnViewStateListener listener) { mDelegate.bindListener(listener); } @Override public Context getContext() { return BaseActivity.this; } @Override public void showToast(String message) { mDelegate.showToast(message); } @Override public void showLoadingDialog(String message) { mDelegate.showLoadingDialog(message); } @Override public void hideLoadingDialog() { mDelegate.hideLoadingDialog(); } }
3、Presenter层代码
-
IPresenter公共接口,因为要监听View生命周期,让它继承OnViewStateListener 接口
public interface IImprovePresenter<M,V extends IView> extends OnViewStateListener { /** * View绑定 * @param v */ void bindView(V v); /** * 数据加载 * @return */ M loadModel(); /** * View解绑 */ void detachView(); }
-
编写BasePresenter,实现部分共方法
public abstract class BaseImprovePresenter<M extends IModel,V extends IView> implements IImprovePresenter<M,V> { private List<String> mMethods; public BaseImprovePresenter(){ this.mMethods = new ArrayList<>(); } @Override public void onCreate() { } @Override public void onPause() { } @Override public void onResume() { } @Override public void onStop() { } @Override public void onDestroy() { } //---------------------模拟需要在生命周期中处理的逻辑-------------------------------------- /** * 添加View生命周期结束时,需要结束的方法名称; * 类似RxJava中添加addSubscription() * @param methodName */ public void addHandleMethod(String methodName){ if (mMethods != null){ mMethods.add(methodName); } } /** * 清楚 * 类似RxJava中添加clearSubscription() */ public void clearMethod(){ if (mMethods != null && !mMethods.isEmpty()){ mMethods.clear(); } } } -
编写Presenter,
public class ImprovePresenter extends BaseImprovePresenter<ImproveModelImpl,IImproveView> { private IImproveView mView; private ImproveModelImpl mModel; @Override public void bindView(IImproveView iImproveView) { this.mView = iImproveView; mModel = loadModel(); mView.showExplain(mModel.getModel().explain); } @Override public ImproveModelImpl loadModel() { addHandleMethod("异步请求数据方法"); return new ImproveModelImpl(); } @Override public void detachView() { clearMethod(); } public void setInfo(String username, String password) { if (mModel != null){ mModel.getModel().setName(username); mModel.getModel().setPassword(password); } } public void getInfoBean(){ mView.showInfo("用户名:"+mModel.getModel().getName()+"\r\n密码:"+mModel.getModel().getPassword()); } } -
编写PresenterProxy代理类
public class ImprovePresenterProxy implements IImprovePresenter<ImproveModelImpl,IImproveView>, View.OnClickListener { private ImprovePresenter mPresenter; private EditText etUserName; private EditText etPassword; private TextView componentShowInfo; private TextView componentExplain; private IImproveView mView; public ImprovePresenterProxy(ImprovePresenter improvePresenter){ //判空 checkPresenter(improvePresenter); //可以考虑依赖注入 方式 this.mPresenter = improvePresenter; loadModel(); } private void checkPresenter(ImprovePresenter improvePresenter) { if (improvePresenter == null){ throw new NotBindPresenterException(); } } @Override public ImproveModelImpl loadModel() { return mPresenter.loadModel(); } @Override public void bindView(IImproveView iImproveView) { checkView(iImproveView); this.mView = iImproveView; mPresenter.bindView(iImproveView); } private void checkView(IImproveView iImproveView) { if (iImproveView == null){ throw new NotBindViewException(); } } @Override public void detachView() { mPresenter.detachView(); } @Override public void onCreate() { //to do something } @Override public void onPause() { //to do something } @Override public void onResume() { //to do something } @Override public void onStop() { //to do something } @Override public void onDestroy() { detachView(); } @Override public void onClick(View view) { int i = view.getId(); if (i == R.id.btn_save) { if (etUserName != null && etPassword != null){ mView.showToast("保存成功"); mPresenter.setInfo(etUserName.getText().toString(),etPassword.getText().toString()); } } else if (i == R.id.btn_get) { mPresenter.getInfoBean(); } else { } } public void setComponentName(EditText etUsername) { this.etUserName = etUsername; } public void setComponentPassword(EditText etPassword) { this.etPassword = etPassword; } public void setComponentShowInfo(TextView componentShowInfo) { this.componentShowInfo = componentShowInfo; } public void setComponentExplain(TextView componentExplain) { this.componentExplain = componentExplain; } }
至此,完成对MVP框架的完善和升级,完善后的MVP能够更好的用于实际生产,做到进一步的代码解耦的目的。并且由于加入了对View生命周期的管理,也很好的解决NullPointException问题。
实际代码请下载或者Frok项目。
项目GitHub地址:https://github.com/ms-liu/ProjectFrameDemo
欢迎大家给出中肯的建议和提高意见,大家一起学习进步。