赞
踩
之前一直对MVP模式理解的不清楚,今天整理一下,理清楚。mvp模式属于Android架构设计。
M-Model-模型、V-View-视图、P-Presenter-表示器。
a 、View: 视图层,对应xml文件与Activity/Fragment;(用户交互相关的操作接口定义)
b 、Presenter: 逻辑控制层,同时持有View和Model对象;(相当于view和model的传话筒)
c 、Model: 实体层,负责获取实体数据(数据操作,通过接口将数据返回给presenter层)
1. mvp模式
2.mvp原理图
model基类,暂时没有什么东西,
- /**
- * model的基类,进行数据获取与传输,presenter持有其引用,调用对应子类的方法
- * 通过接口返回数据给 presenter
- */
-
- public abstract class BaseModel {
-
- }
view基类,有一些常用的方法,放在baseActivity里面实现,需要注意的是setPresenter方法,作用是在activity里面绑定对应的presenter,
- public interface BaseView<P extends BasePresenter> {
- //通用的常见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的引用
- * <p>
- * presenter持有activity的引用,
- * 可以用根据绑定的activity周期,将activity引用手动制空的方式回收,
- * 还可以使用weakReference的方式。
- */
-
- public abstract class BasePresenter<V extends BaseView, M extends BaseModel> {
-
- private M model;
- // private V view;
-
- public WeakReference<V> mViewRef;//view持有activity的引用,防止内存泄漏,使用弱引用
-
-
- public BasePresenter(V view) {
- // 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; }}
- /**
- * 内部获取第i个类型参数的真实类型 ,反射new出对象.但是最后我没有用这个方法,因为获取不到父类的参数类型对象,debug调了很久也不行,
- * 下次有时间再改一下
- */
-
- public class CreateUtil {
-
- public static <T> T getT(Object o, int i) {
- try {
- return ((Class<T>) ((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<P extends BasePresenter> 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<? extends BaseActivity> 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<Presenter> {
- void onLoginSucess(String msg);
- }
-
-
- abstract class Model extends BaseModel {
- public abstract void requesetData(String data, ModelCallBack modelCallBack);
- }
-
- abstract class Presenter extends BasePresenter<View, Model> {
- 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<LoginContract.Presenter> 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();
- }
- }
最后,包的结构如下:
借鉴博客:
https://www.jianshu.com/p/3a17382d44de
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。