T-MVP开发模式

来源:互联网 发布:it服务外包最大 编辑:程序博客网 时间:2024/05/19 23:13

接触到MVP模式已经挺长时间了,好几个月前T-MVP我就看到了,觉得挺有想法的,于是直接就用到了这次项目里,用起来感觉还行,就花时间推荐一下吧。

大家都知道MVP模式都有的几个接口Model,View,Presenter,另外还有一个用于用于存放这几个接口Contract契约类。先看项目的结构吧:


差不多就是这样,Base包中有MVP的三个Base基类,不过没有看到login包中的View,因为这个View就是我们将要创建的Activity。

接着一步一步的的看Contract中的代码:

[java] view plain copy
print?
  1. package com.z2wenfa.tmvpdemo.function.login;  
  2.   
  3.   
  4. import com.z2wenfa.tmvpdemo.base.BaseModel;  
  5. import com.z2wenfa.tmvpdemo.base.BasePresenter;  
  6. import com.z2wenfa.tmvpdemo.base.BaseView;  
  7.   
  8. /** 
  9.  * Created by z2wenfa on 2016/9/1. 
  10.  */  
  11. public interface LoginContract {  
  12.   
  13.     interface View extends BaseView {  
  14.         
  15.     }  
  16.   
  17.     interface Model extends BaseModel {  
  18.           
  19.     }  
  20.   
  21.     abstract static class Presenter extends BasePresenter<Model, View> {  
  22.   
  23.         @Override  
  24.         public void onStart() {  
  25.   
  26.         }  
  27.           
  28.     }  
  29. }  
package com.z2wenfa.tmvpdemo.function.login;import com.z2wenfa.tmvpdemo.base.BaseModel;import com.z2wenfa.tmvpdemo.base.BasePresenter;import com.z2wenfa.tmvpdemo.base.BaseView;/** * Created by z2wenfa on 2016/9/1. */public interface LoginContract {    interface View extends BaseView {    }    interface Model extends BaseModel {    }    abstract static class Presenter extends BasePresenter<Model, View> {        @Override        public void onStart() {        }    }}
我们在Contract中声明MVP个接口所带的方法,这时我们看到BasePresenter带有2个泛型同时还是一个抽象类.

我们先来看下BasePresenter的代码:

[java] view plain copy
print?
  1. package com.z2wenfa.tmvpdemo.base;  
  2.   
  3. import android.content.Context;  
  4.   
  5. import com.z2wenfa.tmvpdemo.util.rxbus.RxManager;  
  6.   
  7.   
  8. /** 
  9.  * T-MVP Presenter基类 
  10.  * Created by baixiaokang on 16/4/22. 
  11.  */  
  12. public abstract class BasePresenter<M, T> {  
  13.     public Context context;  
  14.     public M mModel;  
  15.     public T mView;  
  16.     public RxManager mRxManager = new RxManager();  
  17.   
  18.     public void setVM(T v, M m) {  
  19.         this.mView = v;  
  20.         this.mModel = m;  
  21.         this.onStart();  
  22.   
  23.     }  
  24.   
  25.     public abstract void onStart();  
  26.   
  27.     public void onDestroy() {  
  28.         mRxManager.clear();  
  29.     }  
  30. }  
package com.z2wenfa.tmvpdemo.base;import android.content.Context;import com.z2wenfa.tmvpdemo.util.rxbus.RxManager;/** * T-MVP Presenter基类 * Created by baixiaokang on 16/4/22. */public abstract class BasePresenter<M, T> {    public Context context;    public M mModel;    public T mView;    public RxManager mRxManager = new RxManager();    public void setVM(T v, M m) {        this.mView = v;        this.mModel = m;        this.onStart();    }    public abstract void onStart();    public void onDestroy() {        mRxManager.clear();    }}
其中有2个泛型变量M和T与一个set方法通过set方法将View与Model传入到Presenter中来。

但是怎么将Model与View实例化并且注入今Presenter的呢?

最关键的代码来了:

我们先看一个工具类TUtil:

[java] view plain copy
print?
  1. package com.innostic.application.util;  
  2.   
  3. import java.lang.reflect.ParameterizedType;  
  4.   
  5. /** 
  6.  * 泛型实例化工具类 (MVP模式) 
  7.  * Created by baixiaokang on 16/4/30. 
  8.  */  
  9. public class TUtil {  
  10.     public static <T> T getT(Object o, int i) {  
  11.         try {  
  12.             return ((Class<T>) ((ParameterizedType) (o.getClass()  
  13.                     .getGenericSuperclass())).getActualTypeArguments()[i])  
  14.                     .newInstance();  
  15.         } catch (InstantiationException e) {  
  16.             e.printStackTrace();  
  17.         } catch (IllegalAccessException e) {  
  18.             e.printStackTrace();  
  19.         } catch (ClassCastException e) {  
  20.             e.printStackTrace();  
  21.         }  
  22.         return null;  
  23.     }  
  24.   
  25.     public static Class<?> forName(String className) {  
  26.         try {  
  27.             return Class.forName(className);  
  28.         } catch (ClassNotFoundException e) {  
  29.             e.printStackTrace();  
  30.         }  
  31.         return null;  
  32.     }  
  33. }  
package com.innostic.application.util;import java.lang.reflect.ParameterizedType;/** * 泛型实例化工具类 (MVP模式) * Created by baixiaokang on 16/4/30. */public class TUtil {    public static <T> T getT(Object o, int i) {        try {            return ((Class<T>) ((ParameterizedType) (o.getClass()                    .getGenericSuperclass())).getActualTypeArguments()[i])                    .newInstance();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (ClassCastException e) {            e.printStackTrace();        }        return null;    }    public static Class<?> forName(String className) {        try {            return Class.forName(className);        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        return null;    }}
通过这个类我们可以传入一个对象通过这个对象与泛型所在位置实例化出一个泛型的对象。


再看BaseActivity类:

[java] view plain copy
print?
  1. /** 
  2.  * Activity基类 
  3.  * Created by z2wenfa on 2016/8/25. 
  4.  */  
  5. public abstract class BaseActivity<T extends BasePresenter, E extends BaseModel> extends Activity implements  JumpUtil.JumpInterface {  
  6.     public T mPresenter;  
  7.     public E mModel;  
  8.     private ProgressDialog progressDialog;  
  9.     private ConfirmDialog confirmDialog;  
  10.   
  11.     @Override  
  12.     protected void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         init();  
  15.     }  
  16.   
  17.     protected void init() {  
  18.         getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);  
  19.         setContentView(getLayoutResID());  
  20.         mPresenter = TUtil.getT(this0);  
  21.         mModel = TUtil.getT(this1);  
  22.         if (this instanceof BaseView) mPresenter.setVM(this, mModel);   
  23.     }  
  24.   
  25.     /** 
  26.      * 获得Layout文件id 
  27.      * 
  28.      * @return 
  29.      */  
  30.     protected abstract int getLayoutResID();  
  31.   
  32.   
  33.     protected abstract void initView();  
  34.   
  35.     }  
  36.   
  37.   
  38. }  
/** * Activity基类 * Created by z2wenfa on 2016/8/25. */public abstract class BaseActivity<T extends BasePresenter, E extends BaseModel> extends Activity implements  JumpUtil.JumpInterface {    public T mPresenter;    public E mModel;    private ProgressDialog progressDialog;    private ConfirmDialog confirmDialog;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        init();    }    protected void init() {        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);        setContentView(getLayoutResID());        mPresenter = TUtil.getT(this, 0);        mModel = TUtil.getT(this, 1);        if (this instanceof BaseView) mPresenter.setVM(this, mModel);     }    /**     * 获得Layout文件id     *     * @return     */    protected abstract int getLayoutResID();    protected abstract void initView();    }}
BaseActivity带有两个泛型,分别限制是继承BasePresenter与BaseModel,通过TUtil生成两个Model与Presenter中,同时调用Presenter的setVM方传入View与Model。

此时我们边能够再Activity中通过mPresenter调用Presenter,在Presenter中通过mView与mModel分别调用View与Model了。

Demo代码


最后再给大家提供一个Android Studio的插件用于自动生成MVP模式的接口,这是我根据别人的MVPHepler改的更适合T-MVP。只需要创建在Contract类中使用,边能够自动生成通用的代码,与对应的Model和Presenter类。大家也可以根据自己的需要制作最适合自己的插件。


TMVPHelper插件下载地址

关于这种模式的几种想法:

1.因为是通过Activity的泛型生成的Model与与Presenter,所以Activity中便有了Model的实例能够直接调用Model的方法。但是尽量不要这么做,这样的话就更MVC没什么区别了,Model和View直接就耦合了。

2.因为MVP模式Model不能调用Presenter所以Presenter如何获得Model耗时操作的结果就成了一个问题,T-MVP使用的是Rxjava来处理这个问题,但是如果对Rxjava没那么熟的话那就只能使用一个接口回调的方式了,大家可以自己选择。


T-MVP博客地址:点击打开链接

MVPHelper地址:点击打开链接

Android Studio插件编写:点击打开链接

TMVPHelper源码地址:点击打开链接