带你写一个不一样的MVP开发框架
与孤独为伴,让自己来一场涅槃
项目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数据接口
1234public interface IModel<T> {void setModel(T t);T getModel();}实现IModel接口
123456789101112131415public class ImproveModelImpl implements IModel<ImproveInfoBean>{private ImproveInfoBean mModel;@Overridepublic void setModel(ImproveInfoBean improveInfoBean) {this.mModel = improveInfoBean;}@Overridepublic ImproveInfoBean getModel() {if (this.mModel == null){this.mModel = new ImproveInfoBean();}return mModel;}}
2、View层代码
定义View生命周期监听接口
123456789101112public interface OnViewStateListener {void onCreate();void onPause();void onResume();void onStop();void onDestroy();}定义公共IView接口
123456789101112131415public interface IView {// 绑定对View生命周期监听void bindListener(OnViewStateListener listener);Context getContext();// Toast提示void showToast(String message);//显示加载对话框void showLoadingDialog(String message);// 隐藏加载对话框void hideLoadingDialog();}编写ViewDelegate
对 View操作的委托类,实现IView和OnViewStateListener接口中的方法123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106public class ViewDelegate implements IView,OnViewStateListener {private Context mCtx;private ProgressDialog mProgressDialog;public ViewDelegate(Context context){this.mCtx = context;}private List<OnViewStateListener> mOnViewStateListeners ;@Overridepublic void bindListener(OnViewStateListener listener) {//用数组管理每一个View的生命周期,避免一个页面有多个监听if (mOnViewStateListeners == null){mOnViewStateListeners = new ArrayList<>();mOnViewStateListeners.add(listener);}else {if (!mOnViewStateListeners.contains(listener)){mOnViewStateListeners.add(listener);}}}@Overridepublic Context getContext() {return mCtx;}@Overridepublic void showToast(String message) {if (mCtx != null) {Toast.makeText(mCtx, message, Toast.LENGTH_SHORT).show();}}@Overridepublic void showLoadingDialog(String message) {if (mCtx != null){mProgressDialog = new ProgressDialog(mCtx);}}@Overridepublic void hideLoadingDialog() {if (mProgressDialog != null && mProgressDialog.isShowing()){mProgressDialog.hide();}}//------------------View生命周期管理--------------------------------------------------------@Overridepublic void onCreate() {if (checkListener()){for (OnViewStateListener listener:mOnViewStateListeners) {listener.onCreate();}}}@Overridepublic void onPause() {if (checkListener()){for (OnViewStateListener listener:mOnViewStateListeners) {listener.onPause();}}}@Overridepublic void onResume() {if (checkListener()){for (OnViewStateListener listener:mOnViewStateListeners) {listener.onResume();}}}@Overridepublic void onStop() {if (checkListener()){for (OnViewStateListener listener:mOnViewStateListeners) {listener.onStop();}}}@Overridepublic void onDestroy() {if (checkListener()){for (OnViewStateListener listener:mOnViewStateListeners) {listener.onDestroy();}}}private boolean checkListener(){return mOnViewStateListeners != null && !mOnViewStateListeners.isEmpty();}}编写BaseActivity,在里面实现页面公共操作方法
1234567891011121314151617181920212223242526272829303132333435363738public class BaseActivity extends AppCompatActivity implements IView{private ViewDelegate mDelegate;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);//可以考虑注解创建mDelegate = new ViewDelegate(this);}@Overridepublic void bindListener(OnViewStateListener listener) {mDelegate.bindListener(listener);}@Overridepublic Context getContext() {return BaseActivity.this;}@Overridepublic void showToast(String message) {mDelegate.showToast(message);}@Overridepublic void showLoadingDialog(String message) {mDelegate.showLoadingDialog(message);}@Overridepublic void hideLoadingDialog() {mDelegate.hideLoadingDialog();}}
3、Presenter层代码
- IPresenter公共接口,因为要监听View生命周期,让它继承OnViewStateListener 接口12345678910111213141516171819public interface IImprovePresenter<M,V extends IView> extends OnViewStateListener {/*** View绑定* @param v*/void bindView(V v);/*** 数据加载* @return*/M loadModel();/*** View解绑*/void detachView();}
编写BasePresenter,实现部分共方法
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354public abstract class BaseImprovePresenter<M extends IModel,V extends IView> implements IImprovePresenter<M,V> {private List<String> mMethods;public BaseImprovePresenter(){this.mMethods = new ArrayList<>();}@Overridepublic void onCreate() {}@Overridepublic void onPause() {}@Overridepublic void onResume() {}@Overridepublic void onStop() {}@Overridepublic 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,
1234567891011121314151617181920212223242526272829303132333435public class ImprovePresenter extends BaseImprovePresenter<ImproveModelImpl,IImproveView> {private IImproveView mView;private ImproveModelImpl mModel;@Overridepublic void bindView(IImproveView iImproveView) {this.mView = iImproveView;mModel = loadModel();mView.showExplain(mModel.getModel().explain);}@Overridepublic ImproveModelImpl loadModel() {addHandleMethod("异步请求数据方法");return new ImproveModelImpl();}@Overridepublic 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代理类
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102public 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();}}@Overridepublic ImproveModelImpl loadModel() {return mPresenter.loadModel();}@Overridepublic void bindView(IImproveView iImproveView) {checkView(iImproveView);this.mView = iImproveView;mPresenter.bindView(iImproveView);}private void checkView(IImproveView iImproveView) {if (iImproveView == null){throw new NotBindViewException();}}@Overridepublic void detachView() {mPresenter.detachView();}@Overridepublic void onCreate() {//to do something}@Overridepublic void onPause() {//to do something}@Overridepublic void onResume() {//to do something}@Overridepublic void onStop() {//to do something}@Overridepublic void onDestroy() {detachView();}@Overridepublic 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问题。