美文网首页android实用技术
Android---MVP模式---大道至简

Android---MVP模式---大道至简

作者: liys_android | 来源:发表于2020-02-09 22:24 被阅读0次

    一. 前言

    看了很多关于MVP的文章,有初级篇,高级篇,还有终极篇 等等,给我的感觉就是: 有没有必要封装的那么复杂?

    1. MVP主要解决了什么问题?

    当页面比较复杂时: Activity 处理的东西太多,太杂,所以得按一定的规则分离出来.

    2. 引发常见的问题?

    ① 内存泄露:
    因为P层持有view层的引用, 目前常见的封装方式,基本都解决了这个问题。
    ② 新增的类过多:
    例如:登陆页,ILoginView, LoginP, ILoginP(用于M层回调,非必须), loginM。
    每个页面都要加这几个类, 反正我是写的挺烦的, 也有的兄弟把这个弄成插件,自动生成.
    ③一个V对应多个P(P层复用), 不太友好:
    ④ 学习成本相对比较高:
    特别是:一些高级的封装方式,比如动态代理.
    使用上: 需要关注的类和方法比较多,而且要一一对应.
    封装逻辑比较复杂: 如果别人需要修改,花费时间相对会多一些.

    正因为有了以上的问题,所以才有了后面MVVM模式. 这里就不说了.
    MVP解决方案如下:

    二. 先最终调用效果

    public class LoginActivity extends MvpActivity<LoginPresenter>{
        //...布局等代码忽略
        @Override
        public void init() {
            presenter.login();  //登录
        }
    
        @Override
        public void mvpSuccess(Object data, String type) {  
            //1.只有一个接口的话,直接强转对象
           //2.多个接口回调的话, 根据type判断,强转对象
        }
    }
    
    public class LoginPresenter extends MvpPresenter{
    
        public LoginPresenter(ImvpView imvpView) {
            super(imvpView);
        }
    
        public void login(){  //.....请求
            //成功
            mvpSuccess(new LoginResult("回调对象"), "loginType");
            //失败
            mvpFail(0, "登陆失败", "loginType");
        }
    }
    
    说明:

    1. 一个Presenter,一个接口的话, mvpSuccess回调,直接强转对象
    2. 一个Presenter,多个接口的话, mvpSuccess回调, 根据返回的type强转对象.
    3. 多个Presenter. 如下:mvpSuccess回调,也是根据type强转对象.

    public class LoginActivity extends MvpActivity<LoginPresenter>{
    
        TestPresenter testPresenter;  //其它的 Presenter
    
        @Override
        public void init() {
            testPresenter = new TestPresenter(this);
            testPresenter.test(); //发起请求
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(testPresenter!= null){ //记得解绑
                testPresenter.unbind();
            }
        }
    }
    

    1. 大伙觉得这样的使用方式怎么样呢? 虽然强转类型感觉不太友好,但是总体我觉得方便了很多.
    2. 看到这里,可能还有很多疑问,例如,部分页面失败回调时候需要单独处理怎么办?

    三. 封装过程(主要看V和P层, M层一样的道理)

    1. 总的回调接口ImvpView
    具体方法根据个人需要自定义, 例如:showLoading(String type), dissmiss(String type).

    //回调接口
    public interface ImvpView {
        //成功
        void mvpSuccess(Object data, String type);
        //失败
        void mvpFail(int code, String msg, String type);
    }
    

    2.MvpActivity类:
    ①: 抽象类,实现回调接口ImvpView.
    ②: 重写抽象方法,这样Activity页面需要什么方法就重写什么方法即可.
    ③: 定义一个泛型变量P, 这样无需每个Activity都定义变量P,P的初始化可以用反射, 也可以在具体Activity中new对象.
    ④: onDestroy解绑.

    public abstract class MvpActivity<T extends MvpPresenter> extends BaseActivity implements ImvpView{
    
        public T presenter;
    
        public void layoutBefore(){
            setPresenter();
        }
    
        private void setPresenter(){
                //1. 懒的话可用反射直接创建, 子类无需再new
                //2. 追求性能, 而且不觉得麻烦的话,可以子类new对象.
        }
    
        @Override
        public void mvpFail(int code, String msg, String type) {}
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(presenter != null){
                presenter.unbind();
            }
        }
    
    }
    
    public abstract class BaseActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            layoutBefore();
            setContentView(getLayoutId());
            init();
        }
        public void layoutBefore(){}
        public abstract int getLayoutId();
        public abstract void init();
    
    }
    

    3.MvpPresenter类:
    ①: 主要思想, 提供给子类,调用ImvpView 里的方法,这个类只是加上的非空判断.
    ②: 提供方法:解除与Activity的关联。
    ③: 可扩展自己需要的方法,不会影响其它地方.

    public class MvpPresenter{
    
        ImvpView imvpView;
        String defaultType = ""; //返回类型
    
        public MvpPresenter(ImvpView imvpView){
            this.imvpView = imvpView;
        }
    
        protected void mvpSuccess(Object data, String type){  //成功
            if(imvpView == null){
                return;
            }
            imvpView.mvpSuccess(data, type);
        }
    
        protected void mvpFail(int code, String msg, String type){ //失败
            if(imvpView == null){
                return;
            }
            imvpView.mvpFail(code, msg, type);
        }
    
    
        /**
         * 解绑
         */
        public void unbind(){
            imvpView = null;
        }
    }
    
    
    四: 总结

    1. 学习成本低,使用简单, 封装逻辑简单,小白应该都能看懂.
    调用时: 耦合性低了很多,V层只需关心需要哪些P, P层只需专心拿数据, 完全不需要关注其它类.
    2. 解决了: 内存泄露,P的复用, 类过多 的问题
    3. 扩展性: 在ImvpView, MvpActivity, MvpPresenter三个核心类, 新增功能, 其它地方完全不受影响.
    4.不足: 强转类型感觉不太友好.

    我做过的项目中,觉得这样封装暂时足够用了, 如有不足,欢迎指出。

    最后附上: 反射初始化P的代码:

     /**
         * 初始化Presenter(觉得麻烦可忽略, 因为直接 new即可)
         */
        private void setPresenter(){
            try {
                Type superClass = getClass().getGenericSuperclass();
                Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
                Class<?> clazz = getRawType(type);
                Constructor constructor =clazz.getConstructor(ImvpView.class);
                presenter = (T) constructor.newInstance(this);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // type不能直接实例化对象,通过type获取class的类型,然后实例化对象
        public static Class<?> getRawType(Type type) {
            if (type instanceof Class) {
                return (Class) type;
            } else if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                Type rawType = parameterizedType.getRawType();
                return (Class) rawType;
            } else if (type instanceof GenericArrayType) {
                Type componentType = ((GenericArrayType) type).getGenericComponentType();
                return Array.newInstance(getRawType(componentType), 0).getClass();
            } else if (type instanceof TypeVariable) {
                return Object.class;
            } else if (type instanceof WildcardType) {
                return getRawType(((WildcardType) type).getUpperBounds()[0]);
            } else {
                String className = type == null ? "null" : type.getClass().getName();
                throw new IllegalArgumentException("Expected a Class, ParameterizedType, or GenericArrayType, but <" + type + "> is of type " + className);
            }
        }
    

    相关文章

      网友评论

        本文标题:Android---MVP模式---大道至简

        本文链接:https://www.haomeiwen.com/subject/avfpzctx.html