美文网首页Weli收藏的文章AndroidMvpandroid
Android-->MVP架构进阶(一)

Android-->MVP架构进阶(一)

作者: 皮卡丘520 | 来源:发表于2018-03-29 15:02 被阅读582次

    相信大家一定在用mvp架构去设计App,但是在设计运用的过程中,大家有没有考虑简化代码,View层和Model层会有很多重复的代码,在显示数据之前还需每次判断View!=null,Presenter层每次需要去new Model层的实例,View层还有可能会对应多个Presenter,一个Presenter会有多个Model层等等问题。

    先介绍下MVP

    image.png
    M:Model数据层:访问网络数据层都放在这里 。
    V:View界面层:与View相关的一些操作都写在这里 Activity、Fragment。
    P:Presenter解耦关联层(Model——View)可能还有一些额外的逻辑,数据的一些逻辑。 
    

    下面是小编在设计MVP架构的项目截图

    mvp.png
    base包:用泛型构建基类  
    HttpClient包:用Retrofit访问网络  
    UserInfoContract:协议类,规范一View层、Model层、Presenter层一系列操作  
    UserInfoModel:请求数据
    UserInfoPresenter:连接着View层和Model层,让View层和Model层充分的解耦  
    

    BasePresenter类

    public class BasePresenter<V extends BaseView, M extends BaseModel> {
    private V mView;
    private M mModel;
    
    /**
     * 绑定View
     *
     * @param view
     */
    public void attach(final V view) {
        //动态代理
        mView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //在View层显示数据之前用户可能退出了View层的页面,会在Activity的onDestroy()方法中会把mView置为null
                //由于View层都是接口,这里采用了动态代理,如果在View层显示数据之前用户可能退出了View层的页面,返回null的话,onSuccess()方法不会执行
                if (mView == null) {
                    return null;
                }
                //每次调用View层接口的方法,都会执行这里
                return method.invoke(view, args);
            }
        });
        //动态创建Model?怎么创建创建???用反射创建
        Type[] params = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
        try {
            //最好是判断下类型
            mModel = (M) ((Class) params[1]).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 解绑View
     */
    public void detach() {
        mView = null;
        mModel = null;
    }
    
    public V getView() {
        return mView;
    }
    
    public M getModel() {
        return mModel;
    }
    

    利用泛型动态去构建View层、Model层。Model层创建实例用反射。BasePresenter会持有View层、Model层的引用,由于View都是接口,Activity会实现这个接口的所有方法,Presenter又会去调用这些方法,所以这里采用了动态代理,如果View==null的话(在成功显示数据之前用户可能会退出页面,在onDestory()方法中会解绑View,View会被置为null)不会执行method.invoke()方法,也就是不会执行向服务器请求数据成功的方法。

    BaseMvpActivity

    public abstract class BaseMvpActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView {
        private P mPresenter;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(getLayoutId());
            //创建Presenter,交给子类去实现
            mPresenter = createPresenter();
            //让P层去绑定V
            mPresenter.attach(this);
            initView();
            initData();
    
        }
    
        protected abstract P createPresenter();
    
        protected abstract int getLayoutId();
    
        protected abstract void initView();
    
        protected abstract void initData();
    
        public P getPresenter() {
            return mPresenter;
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mPresenter.detach();
    }
    

    BaseMvpActivity作为基类,创建Presenter,交给子类去实现。

    UserInfoContract类

    public class UserInfoContract {
    //View层
    interface UserInfoView extends BaseView {
        //加载进度条
        void onLoading();
        //成功返回数据
        void onSuccess(User user);
       //返回数据失败
        void onError();
    
    }
    
    //Presenter层
    interface UserInfoPresenter {
        void getUserInfo(String userName);
    }
    
    //Model层,外部只需关心Model返回的数据,无需关心内部细节
    interface UserModel {
        Call<User> getUserInfo(String userName);
    }
    }
    

    UserInfoContract:协议类,规范一View层、Model层、Presenter层一系列操作。

    UserInfoPresenter 类

        public class UserInfoPresenter extends BasePresenter<UserInfoContract.UserInfoView, UserInfoModel> implements UserInfoContract.UserInfoPresenter {
            @Override
            public void getUserInfo(String userName) {
                getView().onLoading();
                getModel().getUserInfo(userName).enqueue(new Callback<User>() {
                    @Override
                    public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
                        getView().onSuccess(response.body());
                    }
        
                    @Override
                    public void onFailure(@Nullable Call<User> call, @Nullable Throwable t) {
                        getView().onError();
                    }
                });
            }
        }
    

    UserInfoPresenter是连接UserInfoView和UseInfoModel的桥梁,也充分体现了View层和Model层解耦。实现了数据逻辑代码,还有可能会实现一些额外的逻辑代码。

    MainActivity类

    public class MainActivity extends BaseMvpActivity<UserInfoPresenter> implements UserInfoContract.UserInfoView {
    private TextView mTextView;
    /**
     * 创建Presenter
     *
     * @return
     */
    @Override
    protected UserInfoPresenter createPresenter() {
        return new UserInfoPresenter();
    }
    
    /**
     * 返回Activity的布局Id
     *
     * @return
     */
    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }
    
    /**
     * 初始化View
     */
    @Override
    protected void initView() {
        mTextView = findViewById(R.id.tv);
    
    }
    
    /**
     * 在这里去请求数据
     */
    @Override
    protected void initData() {
        getPresenter().getUserInfo("Steven");
    }
    
    /**
     * 显示一个加载的进度条
     */
    @Override
    public void onLoading() {
    
    }
    
    /**
     * 请求数据成功回调该方法
     *
     * @param user
     */
    @Override
    public void onSuccess(User user) {
        mTextView.setText("Hello:" + user.getData().getUserName());
    }
    
    /**
     * 请求数据失败回调该方法
     */
    @Override
    public void onError() {
    
    }
    

    这个demo的完整代码地址:https://github.com/StevenYan88/AndroidMvp.git

    以上解决了View层和Model层会有很多重复的代码,在显示数据之前还需每次判断View!=null,Presenter层每次需要去new Model层的实例这几个问题,View层还有可能会对应多个Presenter,一个Presenter会有多个Model层这几个问题还没有解决。下篇博客在写。如有任务问题或者在设计MVP架构时中遇到了哪些问题扫下面的二维码,加微信讨论讨论。

    MVP架构进阶(二)https://www.jianshu.com/p/6326fa62b8aa

    mmqrcode1521688883691.png

    相关文章

      网友评论

      • Todo2:组件化和插件化的开发里程总结
        https://www.jianshu.com/p/df2a6717009d
      • AWeiLoveAndroid:个人不推荐你这种方式,你这是完全照搬谷歌的那种示范操作,其实实际操作中不是很好用的。
        皮卡丘520:@AWeiLoveAndroid 最近在搭mvp架构,也在使用,你有更好的方式吗?
      • 前行的乌龟:看了下你的代码,标准的 Google 范啊,谈谈自己的感受啊。
        1. 不知道你看没看过 MVP 了;类爆炸的文章,我认为当下 Persenter 是无法也不应该在多个 view 之间复用的,Persenter 即使分离 view 与 UI 无关的逻辑代码的,所以一个类型的 activity 、fragment 必然对应一个类型的 Persenter ,那么你 UserInfoContract 中声明的 userActivity 页面的 专用 UserInfoView 接口是没有必要的,泛型 T 传具体的 class 类型就行,view 和 persenter 都传对方具体的类型
        2. 对于 modle 的问题,实际开发中很多时候一个页面有多个业务 API 接口,你这基类里传一个 modle 明显不适用于具体需求场景,不要为了封装而封装,我们既要封装重复代码,也要保持灵活度。P 层中可以不要 modle 的泛型,因为你不知道自己会要几个。
        3. 当下数据层的封装都是按模块来的,同一个模块下的 API 接口封装到一个 respositroy 中,respositroy 持有该模块下的所有 remote,sql,file,cache 数据源。以前的 modle 封装明显不使用于越来越高的需求了,你想想我们做平台化改造,5个 app 使用相同的数据层逻辑,你要怎么封装。
        4. 用过 DataBinding 数据绑定没有,可以往 xml 布局里传 persenter 对象,直接赋值,调用方法。
        5. Google 去年出的 AAC 组件,是对于 MVVM 的加强,AAC + DataBinding+ Rxjava 的组合的确比 MVP 好使多了,建议看下
        ps:多谢关注啊,共同学习
        AWeiLoveAndroid:MVVM目前来说,国内是用的人不算很多,但是思想还是不错的
        皮卡丘520:@前行的乌龟 你的文章也会看看,大家一起讨论下呗
        皮卡丘520:@前行的乌龟 多谢呀。加个微信可否?一起讨论问题,我最近打算写博客

      本文标题:Android-->MVP架构进阶(一)

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