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模式

 

 

MVP模式的理解和整理_第1张图片

                                                2.mvp原理图

 

二.MVP模式优点

MVP模式的理解和整理_第2张图片

 

 

三.MVP模式代码

一、基类

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

/**
 * model的基类,进行数据获取与传输,presenter持有其引用,调用对应子类的方法
 * 通过接口返回数据给 presenter
 */

public abstract class BaseModel {

}

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

public interface BaseView

{ //通用的常见view互动方法,写在基类里面 void showLoading(); void hideLoading(); void showError(String msg, int code); //view绑定presenter的方法,由baseactivity类来实现 void setPresenter(P p); }

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

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

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

/**
 * presenter基类,持有view,model的引用,进行逻辑处理
 * 作为view和model的传话筒,持有 activity的应用,并且setpresenter使activity持有presenter的引用
 * 

* presenter持有activity的引用, * 可以用根据绑定的activity周期,将activity引用手动制空的方式回收, * 还可以使用weakReference的方式。 */ public abstract class BasePresenter { private M model; // private V view; public WeakReference mViewRef;//view持有activity的引用,防止内存泄漏,使用弱引用 public BasePresenter(V view) { // this.model = CreateUtil.getT(this, 1);

//通过反射获取model对象的方法不行,继承关系太多,获取不到相应的对象

// this.view = view; mViewRef = new WeakReference(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; }}

/**
 * 内部获取第i个类型参数的真实类型 ,反射new出对象.但是最后我没有用这个方法,因为获取不到父类的参数类型对象,debug调了很久也不行,
*  下次有时间再改一下
 */

public class CreateUtil {

    public static  T getT(Object o, int i) {
        try {
            return ((Class) ((ParameterizedType) (o.getClass().getGenericSuperclass())).getActualTypeArguments()[i]).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}

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

/**
 * activity基类
 * 对应子类实现对应view接口的方法,持有presenter的引用
 */

public abstract class BaseActivity

extends Activity { private P presenter; public P getPresenter() { return presenter; } public void setPresenter(P presenter) { this.presenter = presenter; } public void showLoading() { } public void hideLoading() { } public void showError(String msg, int code) { } private Bundle bundle; private final String BUNDLE_KEY = "bundle_key"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); bundle = getIntent().getBundleExtra(BUNDLE_KEY); if (bundle == null) { bundle = new Bundle(); } // if (null != presenter) { // presenter.onCreate(); // } } public void startNextStepActivity(Class activity) { Intent intent = new Intent(this, activity); intent.putExtra(BUNDLE_KEY, bundle); startActivity(intent); } public Bundle getBundle() { return bundle; } @Override protected void onStart() { super.onStart(); // if (null != presenter) { // presenter.onStart(); // } } @Override protected void onResume() { super.onResume(); // if (null != presenter) { // presenter.onResume(); // } } @Override protected void onPause() { super.onPause(); // if (null != presenter) { // presenter.onPause(); // } } @Override protected void onStop() { super.onStop(); // if (null != presenter) { // presenter.onStop(); // } } @Override protected void onDestroy() { super.onDestroy(); // if (null != presenter) { // presenter.onDestroy(); // } } }

二、实现类

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

contract接口:

public interface LoginContract {

    interface View extends BaseView {
        void onLoginSucess(String msg);
    }


    abstract class Model extends BaseModel {
        public abstract void requesetData(String data, ModelCallBack modelCallBack);
    }

    abstract class Presenter extends BasePresenter {
        public Presenter(View view) {
            super(view);
        }

        public abstract void login(String name, String password);
    }

    //model向presenter返回数据的接口,方法的数据类型根据需要自定义
    //这个接口也可以整理出通用的,不用每个contract都单独定义
    interface ModelCallBack {
        void onCallBack(String msg);
    }
}

model实现类:

public class LoginModelImpl extends LoginContract.Model {

    @Override
    public void requesetData(String data, final LoginContract.ModelCallBack modelCallBack) {
        //进行网络数据操作等等,
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                modelCallBack.onCallBack("获取的数据");
            }
        }, 2000);

    }
}

presenter实现类:

 

public class LoginPresenterImpl extends LoginContract.Presenter {
   private LoginModelImpl model;
    public LoginPresenterImpl(LoginContract.View view) {
        super(view);
        model =  new LoginModelImpl();
 }

    @Override
    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对象。

public class LoginActivity extends BaseActivity implements View.OnClickListener, LoginContract.View {

    private EditText etUserName;
    private EditText etPassword;
    private Button btnLogin;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        new LoginPresenterImpl(this);//实例化对应的presenter,activity绑定presenter对象
        setTitle("登录");
    }

    private void initView() {
        etUserName = (EditText) findViewById(R.id.et_user_name);
        etPassword = (EditText) findViewById(R.id.et_password);
        btnLogin = (Button) findViewById(R.id.btn_login);

        btnLogin.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_login:
                submit();
                break;
        }
    }

    private void submit() {
        String name = etUserName.getText().toString().trim();
        if (TextUtils.isEmpty(name)) {
            Toast.makeText(this, "用户名为空", Toast.LENGTH_SHORT).show();
            return;
        }

        String password = etPassword.getText().toString().trim();
        if (TextUtils.isEmpty(password)) {
            Toast.makeText(this, "密码为空", Toast.LENGTH_SHORT).show();
            return;
        }

        getPresenter().login(name, password);
    }

    @Override
    public void onLoginSucess(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
}

最后,包的结构如下:

MVP模式的理解和整理_第3张图片

借鉴博客:

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

你可能感兴趣的:(MVP模式的理解和整理)