当前位置:   article > 正文

MVP模式的理解和整理

mvp模式

之前一直对MVP模式理解的不清楚,今天整理一下,理清楚。mvp模式属于Android架构设计。

一.MVP模式介绍

M-Model-模型、V-View-视图、P-Presenter-表示器。

a 、View: 视图层,对应xml文件与Activity/Fragment;(用户交互相关的操作接口定义)

b 、Presenter: 逻辑控制层,同时持有View和Model对象;(相当于view和model的传话筒)

c 、Model: 实体层,负责获取实体数据(数据操作,通过接口将数据返回给presenter层)

                       

                                                  1.  mvp模式

 

 

                                                2.mvp原理图

 

二.MVP模式优点

 

 

三.MVP模式代码

一、基类

model基类,暂时没有什么东西,

  1. /**
  2. * model的基类,进行数据获取与传输,presenter持有其引用,调用对应子类的方法
  3. * 通过接口返回数据给 presenter
  4. */
  5. public abstract class BaseModel {
  6. }

view基类,有一些常用的方法,放在baseActivity里面实现,需要注意的是setPresenter方法,作用是在activity里面绑定对应的presenter,

  1. public interface BaseView<P extends BasePresenter> {
  2. //通用的常见view互动方法,写在基类里面
  3. void showLoading();
  4. void hideLoading();
  5. void showError(String msg, int code);
  6. //view绑定presenter的方法,由baseactivity类来实现
  7. void setPresenter(P p);
  8. }

presenter基类:这里面注释掉的是使用手动回收view对象的方式,后来改成用弱引用了,更优化,防止内存泄漏。

presenter里面有持有model对象,怎么初始化这个model对象,我想了好久,对比了好几个方法,刚开始是在presenter的构造方法里面,传递过来model对象,但是presenter的初始化,是在对应的activity里面,那样activity里面就要有model对象,虽然没有操作model的方法,但是感觉持有对象了,也不算完全解耦了,最后找到了这个方法,getGenericSuperclass,可以直接获取泛型参数类型的真实类型,反射出new 对象。

我的presenter对象是在对应的activity里面初始化的,没有直接在activity基类里面实例化,而是哪个activity需要对应的presenter的时候,在对应activity里面初始化,因为感觉有些小的activity里面不需要presenter等等,很简单的,就不需要都写了。

  1. /**
  2. * presenter基类,持有view,model的引用,进行逻辑处理
  3. * 作为view和model的传话筒,持有 activity的应用,并且setpresenter使activity持有presenter的引用
  4. * <p>
  5. * presenter持有activity的引用,
  6. * 可以用根据绑定的activity周期,将activity引用手动制空的方式回收,
  7. * 还可以使用weakReference的方式。
  8. */
  9. public abstract class BasePresenter<V extends BaseView, M extends BaseModel> {
  10. private M model;
  11. // private V view;
  12. public WeakReference<V> mViewRef;//view持有activity的引用,防止内存泄漏,使用弱引用
  13. public BasePresenter(V view) {
  14. // this.model = CreateUtil.getT(this, 1);
//通过反射获取model对象的方法不行,继承关系太多,获取不到相应的对象

// this.view = view; mViewRef = new WeakReference<V>(view); mViewRef.get().setPresenter(this); } public M getModel() { return model; } public V getView() { if (isAttach()) { return mViewRef.get(); } else { return null; } } public void onDetatch() { if (null != mViewRef) { mViewRef.clear(); mViewRef = null; } } private boolean isAttach() { return null != mViewRef && null != mViewRef.get(); } // public V getView() { // return view; // }// 和baseActivity里的生命周期绑定 public void onCreate() { } public void onStart() { } public void onResume() { } public void onPause() { } public void onStop() { } public void onDestroy() { model = null; // view = null; }}

  1. /**
  2. * 内部获取第i个类型参数的真实类型 ,反射new出对象.但是最后我没有用这个方法,因为获取不到父类的参数类型对象,debug调了很久也不行,
  3. * 下次有时间再改一下
  4.  */
  5. public class CreateUtil {
  6. public static <T> T getT(Object o, int i) {
  7. try {
  8. return ((Class<T>) ((ParameterizedType) (o.getClass().getGenericSuperclass())).getActualTypeArguments()[i]).newInstance();
  9. } catch (Exception e) {
  10. e.printStackTrace();
  11. }
  12. return null;
  13. }
  14. }

activity基类:setPresenter  showLoading hideLoading showError方法都是提前实现的view接口的,这样activity子类就不需要在每个都实现这些都需要的方法了,下面声明周期相关的,是前面presenter里面,如过没有使用使用弱引用获取view对象的方式,手动释放view对象要使用的方法。

  1. /**
  2. * activity基类
  3. * 对应子类实现对应view接口的方法,持有presenter的引用
  4. */
  5. public abstract class BaseActivity<P extends BasePresenter> extends Activity {
  6. private P presenter;
  7. public P getPresenter() {
  8. return presenter;
  9. }
  10. public void setPresenter(P presenter) {
  11. this.presenter = presenter;
  12. }
  13. public void showLoading() {
  14. }
  15. public void hideLoading() {
  16. }
  17. public void showError(String msg, int code) {
  18. }
  19. private Bundle bundle;
  20. private final String BUNDLE_KEY = "bundle_key";
  21. @Override
  22. protected void onCreate(@Nullable Bundle savedInstanceState) {
  23. super.onCreate(savedInstanceState);
  24. bundle = getIntent().getBundleExtra(BUNDLE_KEY);
  25. if (bundle == null) {
  26. bundle = new Bundle();
  27. }
  28. // if (null != presenter) {
  29. // presenter.onCreate();
  30. // }
  31. }
  32. public void startNextStepActivity(Class<? extends BaseActivity> activity) {
  33. Intent intent = new Intent(this, activity);
  34. intent.putExtra(BUNDLE_KEY, bundle);
  35. startActivity(intent);
  36. }
  37. public Bundle getBundle() {
  38. return bundle;
  39. }
  40. @Override
  41. protected void onStart() {
  42. super.onStart();
  43. // if (null != presenter) {
  44. // presenter.onStart();
  45. // }
  46. }
  47. @Override
  48. protected void onResume() {
  49. super.onResume();
  50. // if (null != presenter) {
  51. // presenter.onResume();
  52. // }
  53. }
  54. @Override
  55. protected void onPause() {
  56. super.onPause();
  57. // if (null != presenter) {
  58. // presenter.onPause();
  59. // }
  60. }
  61. @Override
  62. protected void onStop() {
  63. super.onStop();
  64. // if (null != presenter) {
  65. // presenter.onStop();
  66. // }
  67. }
  68. @Override
  69. protected void onDestroy() {
  70. super.onDestroy();
  71. // if (null != presenter) {
  72. // presenter.onDestroy();
  73. // }
  74. }
  75. }

二、实现类

以login登录的方法为例子。这里使用了contract接口,是为了代码更整洁一些,将基类放一起。

contract接口:

  1. public interface LoginContract {
  2. interface View extends BaseView<Presenter> {
  3. void onLoginSucess(String msg);
  4. }
  5. abstract class Model extends BaseModel {
  6. public abstract void requesetData(String data, ModelCallBack modelCallBack);
  7. }
  8. abstract class Presenter extends BasePresenter<View, Model> {
  9. public Presenter(View view) {
  10. super(view);
  11. }
  12. public abstract void login(String name, String password);
  13. }
  14. //model向presenter返回数据的接口,方法的数据类型根据需要自定义
  15. //这个接口也可以整理出通用的,不用每个contract都单独定义
  16. interface ModelCallBack {
  17. void onCallBack(String msg);
  18. }
  19. }

model实现类:

  1. public class LoginModelImpl extends LoginContract.Model {
  2. @Override
  3. public void requesetData(String data, final LoginContract.ModelCallBack modelCallBack) {
  4. //进行网络数据操作等等,
  5. new Handler().postDelayed(new Runnable() {
  6. @Override
  7. public void run() {
  8. modelCallBack.onCallBack("获取的数据");
  9. }
  10. }, 2000);
  11. }
  12. }

presenter实现类:

 

  1. public class LoginPresenterImpl extends LoginContract.Presenter {
  2. private LoginModelImpl model;
  3. public LoginPresenterImpl(LoginContract.View view) {
  4. super(view);
  5.         model =  new LoginModelImpl();
  6.  }
  7. @Override
  8. public void login(String name, String password) {
    model.requesetData(name + password, new LoginContract.ModelCallBack() {

@Override public void onCallBack(String msg) { getView().onLoginSucess(msg); } }); }}view的实习类:重要的是oncreate里面 new 出来的对应的presenter对象,会调用到presenter基类里面绑定view.setPresenter方法,使得activity获取到presenter的对象。下面可以直接getPresenter()方法来获取presenter对象。

  1. public class LoginActivity extends BaseActivity<LoginContract.Presenter> implements View.OnClickListener, LoginContract.View {
  2. private EditText etUserName;
  3. private EditText etPassword;
  4. private Button btnLogin;
  5. @Override
  6. protected void onCreate(@Nullable Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_main);
  9. initView();
  10. new LoginPresenterImpl(this);//实例化对应的presenter,activity绑定presenter对象
  11. setTitle("登录");
  12. }
  13. private void initView() {
  14. etUserName = (EditText) findViewById(R.id.et_user_name);
  15. etPassword = (EditText) findViewById(R.id.et_password);
  16. btnLogin = (Button) findViewById(R.id.btn_login);
  17. btnLogin.setOnClickListener(this);
  18. }
  19. @Override
  20. public void onClick(View v) {
  21. switch (v.getId()) {
  22. case R.id.btn_login:
  23. submit();
  24. break;
  25. }
  26. }
  27. private void submit() {
  28. String name = etUserName.getText().toString().trim();
  29. if (TextUtils.isEmpty(name)) {
  30. Toast.makeText(this, "用户名为空", Toast.LENGTH_SHORT).show();
  31. return;
  32. }
  33. String password = etPassword.getText().toString().trim();
  34. if (TextUtils.isEmpty(password)) {
  35. Toast.makeText(this, "密码为空", Toast.LENGTH_SHORT).show();
  36. return;
  37. }
  38. getPresenter().login(name, password);
  39. }
  40. @Override
  41. public void onLoginSucess(String msg) {
  42. Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
  43. }
  44. }

最后,包的结构如下:

借鉴博客:

https://www.jianshu.com/p/3a17382d44de

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/286321
推荐阅读
相关标签
  

闽ICP备14008679号