美文网首页android技术RX Java强大的异步实现库
Android MVP开发模式与Rxjava+Retrofit结

Android MVP开发模式与Rxjava+Retrofit结

作者: 刘坤林 | 来源:发表于2021-10-16 15:21 被阅读0次

    简述

    直接起飞
    本文章主要详细展示了安卓mvp开发模式中如何优雅的结合Rxjava+Retrofit,完成我们的接口调用。我自称其模式为“MCP”模式,该模式介绍如下

    mcp模式示意图
    ①Model层:处理网络请求,设定网络框架中的回调线程等
    ②Contract层:契约层,主要定义了各种类型下的View和Presenter,这也是MCP中尤为重要的存在,是用户界面和网络接口需求的定义。
    ③Presenter层:用户直接可以直接操作到的一层。将Model层的结果回调给View层,取消Model和View的绑定、主动取消网络请求等。
    如此一来,model层和presente紧密结合,presenter的使用很灵活,而model层和view层没有任何关系,同时presenter与view'层可完全解耦。

    为什么叫mcp

    图示中要么就是mvp要么就是mc,怎么会mcp呢?这并不是乱来的,model层相当于rxjava+Retrofit了,定义不变;c是契约类,定义了需要实现的view和presenter,定义也不变;p实际上是BasePresenter<T,M,V>.class一个类,这个类在使用过程中不需要重复定义,但它需要统一处理model返回的数据,绑定和解绑view,更是重中之重,所以不能忽略。

    具体实现

    需求定义(登录模块功能,用户模块)

    日常开发中,业务逻辑都不会太简单,因此需要将很多功能模块化,如
    将登录、注册、忘记密码归为“登录模块”,因此,只需要一个契约类“IContractLogin”即可;
    用户信息方面,获取用户信息、修改用户信息也可以归为“用户模块”,契约类为“IContractUser”;

    基础代码

    得益于很多大神们的优秀博客,我自称的mcp模式下也是有对应的基础代码的。

    一、项目配置和项目目录

    1.app的build.gradle文件的部分配置如下

    android{
        ......//applicationId、版本等
        //启用viewbinding
        buildFeatures {
            viewBinding true
        }
        //签名
        signingConfigs {
            def alias = 'key0'
            def password = '123456'
            def filePath = '../mcp.jks'
            debug {
                keyAlias alias
                keyPassword password
                storeFile file(filePath)
                storePassword(password)
            }
            release {
                keyAlias alias
                keyPassword password
                storeFile file(filePath)
                storePassword(password)
            }
        }
        //打包的apk名称
        applicationVariants.all { variant ->
            variant.outputs.all {
                outputFileName = "mcp.apk"
            }
        }
    }
    

    引入所需要的的包,这里我已经习惯了引入这些东西,懒得删掉了,反正以后要用。

        //网络
        //noinspection GradleDependency
        implementation 'com.squareup.retrofit2:retrofit:2.5.0'
        implementation 'com.squareup.retrofit2:converter-scalars:2.5.0'
        //noinspection GradleDependency
        implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
        //noinspection GradleDependency
        implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
        //noinspection GradleDependency
        implementation 'com.squareup.okhttp3:okhttp:3.12.8'
        implementation 'com.squareup.okhttp3:logging-interceptor:3.12.8'
        //noinspection GradleDependency
        implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
        //图片选择器
        implementation group: 'com.github.LuckSiege.PictureSelector', name: 'picture_library', version: 'v2.6.0'
        //gilde图片加载器
        //noinspection GradleDependency
        implementation 'com.github.bumptech.glide:glide:4.5.0'
        //noinspection GradleDependency
        annotationProcessor 'com.github.bumptech.glide:compiler:4.5.0'
    

    记得加上仓库地址


    image.png
           maven { url "https://jitpack.io" }
            maven { url 'http://central.maven.org/maven2/' }
    

    2.修改gradle.properties文件

    gradle.properties修改前

    修改为


    gradle.properties修改后
    # Automatically convert third-party libraries to use AndroidX
    android.enableJetifier=true
    

    3.项目目录结构

    详细的项目接口示意图

    看起来好像好乱,收起再看就舒服多了


    目录结构

    二、代码实现

    基类和接口

    这里只剩下p层和v层的基类了,因为m层已经完全融入到rxjava中了。
    IBasePresenter接口,在契约类中,所有的presenter都要继承于它。

    public interface IBasePresenter<T> {
        /**
         * 设定类型
         *
         * @param i 默认为0
         */
        void setType ( int i );
    
        /**
         * 添加请求列表
         *
         * @param disposable 实体
         */
        void add ( Disposable disposable );
    
        /**
         * 解绑
         */
        void detachView ( );
    
        /**
         * 视图回调
         *
         * @param data 数据
         */
        void viewCallBack (  CallResult< T > data );
    
        /**
         * 视图回调
         *
         * @param e 异常
         */
        void viewCallBack (  Throwable e );
    }
    

    同时,presenter需要处理View和model,所以他有一个实现类。你别看代码多,实际开发中,这类完全不需要动它,而且因为有了它,我们在新建presenter的时候,少很多功夫,而且新建的presenter只要继承了它,代码都能规范很多。这里需要提一下的方法是“add()”方法,它是将某次请求添加到请求队列中,当detachView()被调用,未完成的网络请求会被取消。

    public abstract class BasePresenter< T, M, V extends IBaseView< T > >
            implements IBasePresenter< T > {
        public static final int UNAUTHORIZED = 401;
        public static final int SUCCESS = 200;
        public static final int FORBIDDEN = 403;
        public static final int NOT_FOUND = 404;
        public static final int REQUEST_TIMEOUT = 408;
        public static final int INTERNAL_SERVER_ERROR = 500;
        public static final int BAD_GATEWAY = 502;
        public static final int SERVICE_UNAVAILABLE = 503;
        public static final int GATEWAY_TIMEOUT = 504;
        /**
         * 默认页页面大小
         */
        protected static final int PAGE_SIZE = 10;
        /**
         * 视图层
         */
        private V view;
        /**
         * model层
         */
        protected M module;
        /**
         * 视图引用
         */
        private WeakReference< V > weakReference;
        /**
         * 主线程
         */
        protected final Handler handler;
        /**
         * 请求列表
         */
        protected final List< Disposable > disposables = new ArrayList<> ( );
        /**
         * 有时候,删除和修改共用一个presenter,需要用一个标记将它们却别
         */
        private int type = 0;
    
        /**
         * 构造方法
         *
         * @param view 视图实现类
         */
        public BasePresenter ( V view ) {
            this.attachView ( view );
            this.handler = new Handler ( Looper.getMainLooper ( ) );
        }
    
        /**
         * 绑定
         *
         * @param view 视图
         */
        public void attachView ( V view ) {
            if ( view != null ) {
                this.weakReference = new WeakReference<> ( view );
                this.view = ( V ) Proxy.newProxyInstance ( view.getClass ( ).getClassLoader ( ),
                        view.getClass ( ).getInterfaces ( ),
                        new MvpViewHandler ( this.weakReference.get ( ) ) );
            }
    
            if ( this.module == null ) {
                this.module = this.createModule ( );
            }
        }
    
        /**
         * 登录的token
         *
         * @return Strung
         */
        protected String token ( ) {
            return LoginUtils.getToken ( );
        }
    
        @Override
        public void detachView ( ) {
            this.module = null;
            this.handler.removeCallbacksAndMessages ( null );
            if ( this.isViewAttached ( ) && this.weakReference != null ) {
                this.weakReference.clear ( );
                this.weakReference = null;
            }
            this.view = null;
            try {
                for ( Disposable disposable : disposables ) {
                    if ( ! disposable.isDisposed ( ) ) {
                        disposable.dispose ( );
                    }
                }
            } catch ( Exception e ) {
                Logger.e ( e );
            }
        }
    
        protected boolean isViewAttached ( ) {
            return this.view != null && this.weakReference != null && this.weakReference.get ( ) != null;
        }
    
        /**
         * 创建module
         *
         * @return M
         */
        protected abstract M createModule ( );
    
        /**
         * 请求是否成功
         *
         * @param callResult 响应体
         * @return 成功true,失败false
         */
        protected boolean isSuccess ( CallResult< T > callResult ) {
            return callResult != null && callResult.code == SUCCESS;
        }
    
        /**
         * 设定类型
         *
         * @param type 默认0
         */
        @Override
        public void setType ( int type ) {
            this.type = type;
        }
    
        /**
         * 添加到请求列表
         *
         * @param disposable 实体
         */
        @Override
        public void add ( Disposable disposable ) {
            disposables.add ( disposable );
        }
    
        /**
         * 视图回调---成功
         * 如果回调的线程不是主线程,则在主线程回调
         *
         * @param data 数据
         */
        @Override
        public void viewCallBack ( CallResult< T > data ) {
            if ( Looper.myLooper ( ) == Looper.getMainLooper ( ) ) {
                viewCallBackSuccess ( data );
            } else {
                handler.post ( ( ) -> viewCallBackSuccess ( data ) );
            }
        }
    
        /**
         * 视图回调---失败
         * 如果回调的线程不是主线程,则在主线程回调
         *
         * @param e 异常
         */
        @Override
        public void viewCallBack ( Throwable e ) {
            if ( Looper.myLooper ( ) == Looper.getMainLooper ( ) ) {
                viewCallBackError ( e );
            } else {
                handler.post ( ( ) -> viewCallBackError ( e ) );
            }
        }
    
        /**
         * 接口调用成功的后回调
         *
         * @param data data
         */
        private void viewCallBackSuccess ( CallResult< T > data ) {
            if ( isViewAttached ( ) ) {
                view.onCallBack ( type, data.code == SUCCESS, data.message, data.data );
            }
        }
    
        /**
         * 接口调用失败的回调
         *
         * @param e 异常
         */
        private void viewCallBackError ( Throwable e ) {
            if ( isViewAttached ( ) ) {
                try {
                    if ( e instanceof HttpException ) {
                        HttpException httpException = ( HttpException ) e;
                        switch ( httpException.code ( ) ) {
                            case UNAUTHORIZED:
                                view.onCallBack ( type, false, "登录验证已过期", null );
                                break;
                            case INTERNAL_SERVER_ERROR:
                                view.onCallBack ( type, false, "服务器错误", null );
                                break;
                            case FORBIDDEN:
                            case NOT_FOUND:
                                view.onCallBack ( type, false, "无效的请求", null );
                                break;
                            case REQUEST_TIMEOUT:
                            case GATEWAY_TIMEOUT:
                            case BAD_GATEWAY:
                            case SERVICE_UNAVAILABLE:
                            default:
                                view.onCallBack ( type, false, httpException.getMessage ( ), null );
                                break;
                        }
                    } else if ( e instanceof ConnectException ) {
                        view.onCallBack ( type, false, "网络连接异常,请检查您的网络状态", null );
                    } else if ( e instanceof SocketTimeoutException ) {
                        view.onCallBack ( type, false, "网络连接超时,请检查您的网络状态,稍后重试", null );
                    } else if ( e instanceof UnknownHostException ) {
                        view.onCallBack ( type, false, "网络异常,请检查您的网络状态", null );
                    } else if ( e instanceof JsonParseException
                            || e instanceof JSONException
                            || e instanceof ParseException ) {
                        view.onCallBack ( type, false, "数据解析错误", null );
                    } else if ( e instanceof SSLHandshakeException ) {
                        view.onCallBack ( type, false, "证书验证失败", null );
                    } else if ( e instanceof RuntimeException ) {
                        view.onCallBack ( type, false, "运行时异常", null );
                    } else {
                        view.onCallBack ( type, false, e.toString ( ), null );
                    }
                } catch ( Exception e1 ) {
                    Logger.e ( e1 );
                }
            }
    
        }
    
        protected Map< String, Object > createMap ( int initSize ) {
            return new HashMap<> ( initSize );
        }
    
        protected Map< String, Integer > createMapInt ( int initSize ) {
            return new HashMap<> ( initSize );
        }
    
        protected Map< String, String > createMapStr ( int initSize ) {
            return new HashMap<> ( initSize );
        }
    
    
        private class MvpViewHandler implements InvocationHandler {
            private final IBaseView< ? > mvpView;
    
            MvpViewHandler ( IBaseView< ? > mvpView ) {
                this.mvpView = mvpView;
            }
    
            @Override
            @SuppressWarnings ( "SuspiciousInvocationHandlerImplementation" )
            public Object invoke ( Object proxy, Method method, Object[] args ) throws Throwable {
                if ( isViewAttached ( ) ) {
                    return method.invoke ( this.mvpView, args );
                }
                return null;
            }
        }
    }
    

    IBaseView接口,在契约类中,所有的view都要继承于它。就是通过继承它,才把接口回调的形式全部都统一起来的。

    public interface IBaseView<T> {
        /**
         * ui回调
         *
         * @param i    类型
         * @param b    是否请求成功
         * @param s    描述
         * @param data 泛型
         */
        void onCallBack ( int i, boolean b, String s, T data );
    }
    

    M层代码

    model层,其实就是100%的rxjava层。这里的代码都是要手动编写的,与我们后端的接口基本上对应起来

    public interface IBaseModel {
        /**
         * 登录
         *
         * @param data 登录参数
         */
        @POST ( "/mcpdemo/api/user/login" )
        Observable< CallResult< LoginResponse > > login ( @Body Map< String, String > data );
    
        /**
         * 注册
         *
         * @param data 注册参数
         */
        @POST ( "/mcpdemo/api/user/register" )
        Observable< CallResult< Void > > register ( @Body Map< String, Object > data );
    
        /***
         * 忘记密码
         * @param data  忘记密码参数
         */
        @POST ( "/mcpdemo/api/user/forget" )
        Observable< CallResult< Void > > forgetPwd ( @Body Map< String, String > data );
    
        /**
         * 获取用户信息
         *
         * @param token 登录后的token
         */
        @GET ( "/mcpdemo/api/user/detail" )
        Observable< CallResult< UserInfo > > userInfo ( @Header ( "token" ) String token );
    
        /**
         * 更新用户信息,修改个人资料
         *
         * @param token token
         * @param info  info
         */
        @POST ( "/mcpdemo/api/user/update" )
        Observable< CallResult< Void > > userInfoUpdate ( @Header ( "token" ) String token,
                                                          @Body UserInfo info );
    }
    

    再看看他的实现类。在这里你可以统一定义观察者和被观察者的线程,无所谓的,反正到了p层会在ui线程回调。别看他代码多,编译器会帮你生成方法的,你只需要填写方法内容即可。

    public class BaseModel implements IBaseModel {
        private static IBaseModel api;
        private static BaseModel instance;
    
        public static BaseModel instance ( ) {
            if ( instance == null ) {
                instance = new BaseModel ( );
            }
            return instance;
        }
    
        private BaseModel ( ) {
            api = Retrofit2Manager.with ( UrlUtils.URL ).retrofit ( ).create ( IBaseModel.class );
        }
    
        @Override
        public Observable< CallResult< LoginResponse > > login ( Map< String, String > data ) {
            return api.login ( data ).subscribeOn ( Schedulers.io ( ) )
                    .observeOn ( AndroidSchedulers.mainThread ( ) );
        }
    
        @Override
        public Observable< CallResult< Void > > register ( Map< String, Object > data ) {
            return api.register ( data ).subscribeOn ( Schedulers.io ( ) )
                    .observeOn ( AndroidSchedulers.mainThread ( ) );
        }
    
        @Override
        public Observable< CallResult< Void > > forgetPwd ( Map< String, String > data ) {
            return api.forgetPwd ( data ).subscribeOn ( Schedulers.io ( ) )
                    .observeOn ( AndroidSchedulers.mainThread ( ) );
        }
    
        @Override
        public Observable< CallResult< UserInfo > > userInfo ( String token ) {
            return api.userInfo ( token ).subscribeOn ( Schedulers.io ( ) )
                    .observeOn ( AndroidSchedulers.mainThread ( ) );
        }
    
        @Override
        public Observable< CallResult< Void > > userInfoUpdate ( String token, UserInfo info ) {
            return api.userInfoUpdate ( token, info ).subscribeOn ( Schedulers.io ( ) )
                    .observeOn ( AndroidSchedulers.mainThread ( ) );
        }
    }
    

    C层代码(定义Presenter和View)

    登录模块契约类。为什么注册和忘记密码不用分开声明?因为它们的回调结果是一样的(Void),我们只需要通过p层的type将它们区分开即可。你可以理解为,只要回调结果是一样的,都能合并在同一个presenter中,这样的话,presenter的实现类的数量会少很多。

    public interface IContractLogin {
        interface IViewLogin extends IBaseView< LoginResponse > {
    
        }
    
        interface IPresenterLogin extends IBasePresenter< LoginResponse > {
            void login ( String phone, String passWord );
        }
    
    
        interface IViewLoginAction extends IBaseView< Void > {
    
        }
    
        interface IPresenterLoginAction extends IBasePresenter< Void > {
            /**
             * 注册-----(i为1)
             *
             * @param phone    手机号
             * @param passWord 密码
             * @param sex      性别1男2女3保密
             */
            void register ( String phone, String passWord, int sex );
    
            /**
             * 忘记密码-----(i为2)
             *
             * @param phone       手机号
             * @param newPassword 新密码
             */
            void forgetPassword ( String phone, String newPassword );
        }
    }
    

    用户模块契约类。token不是activity层(用户)关注的东西,因此获取个人信息这里,不需要传参token,在定义好的基类BasePresenter取就好了。

    public interface IContractUser {
        /**
         * 获取个人信息
         */
        interface IViewUserInfo extends IBaseView< UserInfo > {
    
        }
    
        interface IPresenterUserInfo extends IBasePresenter< UserInfo > {
            void getInfo ( );
        }
    
        /**
         * 更新用户信息
         */
        interface IViewUserAction extends IBaseView< Void > {
    
        }
    
        interface IPresenterUserAction extends IBasePresenter< Void > {
            void update ( UserInfo info );
        }
    }
    

    P层代码

    登录

    public class PresenterLogin extends BasePresenter< LoginResponse, IBaseModel,
            IContractLogin.IViewLogin >
            implements IContractLogin.IPresenterLogin {
        public PresenterLogin ( IContractLogin.IViewLogin view ) {
            super ( view );
        }
    
        @Override
        protected IBaseModel createModule ( ) {
            return BaseModel.instance ( );
        }
    
        @Override
        public void login ( String phone, String passWord ) {
            Map< String, String > map = createMapStr ( 2 );
            map.put ( "phone", phone );
            map.put ( "passWord", passWord );
            add ( module.login ( map ).subscribe ( result -> {
                if ( isSuccess ( result ) ) {
                    //如果登录成功了,保存登录信息
                    LoginUtils.loginSuccess ( result.data );
                }
                //UI回调
                viewCallBack ( result );
            }, this :: viewCallBack ) );
        }
    }
    

    注册和忘记密码

    public class PresenterLoginAction extends BasePresenter< Void, IBaseModel,
            IContractLogin.IViewLoginAction >
            implements IContractLogin.IPresenterLoginAction {
        public PresenterLoginAction ( IContractLogin.IViewLoginAction view ) {
            super ( view );
        }
    
        @Override
        protected IBaseModel createModule ( ) {
            return BaseModel.instance ( );
        }
    
        @Override
        public void register ( String phone, String passWord, int sex ) {
            //设置类型为1,回调的类型则为1
            setType ( 1 );
            Map< String, Object > map = createMap ( 3 );
            map.put ( "phone", phone );
            map.put ( "passWord", passWord );
            map.put ( "sex", sex );
            add ( module.register ( map ).subscribe ( this :: viewCallBack, this :: viewCallBack ) );
        }
    
        @Override
        public void forgetPassword ( String phone, String newPassword ) {
            //设置类型为2,回调的类型则为2
            setType ( 2 );
            Map< String, String > map = createMapStr ( 2 );
            map.put ( "phone", phone );
            map.put ( "newPassword", newPassword );
            add ( module.forgetPwd ( map ).subscribe ( this :: viewCallBack, this :: viewCallBack ) );
        }
    }
    

    获取用户信息

    public class PresenterUserInfo extends BasePresenter< UserInfo, IBaseModel,
            IContractUser.IViewUserInfo >
            implements IContractUser.IPresenterUserInfo {
        public PresenterUserInfo ( IContractUser.IViewUserInfo view ) {
            super ( view );
        }
    
        @Override
        protected IBaseModel createModule ( ) {
            return BaseModel.instance ( );
        }
    
        @Override
        public void getInfo ( ) {
            add ( module.userInfo ( token ( ) )
                    .subscribe ( this :: viewCallBack, this :: viewCallBack ) );
        }
    }
    

    更新用户信息

    public class PresenterUserAction extends BasePresenter< Void, IBaseModel,
            IContractUser.IViewUserAction >
            implements IContractUser.IPresenterUserAction {
        public PresenterUserAction ( IContractUser.IViewUserAction view ) {
            super ( view );
        }
    
        @Override
        protected IBaseModel createModule ( ) {
            return BaseModel.instance ( );
        }
    
        @Override
        public void update ( UserInfo info ) {
            add ( module.userInfoUpdate ( token ( ), info )
                    .subscribe ( this :: viewCallBack, this :: viewCallBack ) );
        }
    }
    

    小结:从以上的presenter实现类可以看出来,大概有2类特点,一种是回调具体的数据,另一种是回调的Void;每种的写法都大同小异。实现类中,代码的样式基本上都是统一的,规则都是:构造方法-->获取model-->执行方法-->回调ui

    三、activity如何使用mcp

    1. 登录模块(包含登录、注册、忘记密码(暂不展示))

    1.1 登录

    public class LoginActivity extends BaseActivity< ActivityLoginBinding > {
    
        @Override
        public ActivityLoginBinding setBaseView ( ) {
            return ActivityLoginBinding.inflate ( getLayoutInflater ( ) );
        }
    
        @Override
        public void onBaseCreate ( ) {
            //实例化登录操作
            IContractLogin.IPresenterLogin presenterLogin = new PresenterLogin ( ( i, b, s, data ) -> {
                //登录回调
                if ( b ) {
                    openActivity ( MainActivity.class );
                    toastAndFinish ( "登录成功" );
                } else {
                    toast ( s );
                }
            } );
            //添加到presenter列表
            addPresenter ( presenterLogin );
            //登录按钮点击事件
            view.btn.setOnClickListener ( v -> {
                String phone = getPhone ( );
                if ( TextUtils.isEmpty ( phone ) ) {
                    toast ( "请输入手机号" );
                    return;
                }
                String pwd = getPwd ( );
                if ( TextUtils.isEmpty ( pwd ) ) {
                    toast ( "请输入密码" );
                    return;
                }
                //开始调用登录接口
                presenterLogin.login ( phone, pwd );
            } );
        }
    
        private String getPhone ( ) {
            return view.edtPhone.getText ( ).toString ( );
        }
    
        private String getPwd ( ) {
            return view.edtPwd.getText ( ).toString ( );
        }
    }
    

    1.2 注册

    public class RegisterActivity extends BaseActivity< ActivityRegisterBinding > {
    
        @Override
        public ActivityRegisterBinding setBaseView ( ) {
            return ActivityRegisterBinding.inflate ( getLayoutInflater ( ) );
        }
    
        @Override
        public void onBaseCreate ( ) {
            IContractLogin.IPresenterLoginAction presenter =
                    new PresenterLoginAction ( ( i, b, s, data ) -> {
                        //i==1虽然有设置i的类型,但由于注册和忘记密码不可能在同一个时刻操作,在这里不用做判断
                        if ( b ) {
                            setResult ( RESULT_OK );
                            toastAndFinish ( "注册成功" );
                        } else {
                            toast ( s );
                        }
                    } );
            //添加到presenter列表
            addPresenter ( presenter );
            //注册按钮点击事件
            view.btn.setOnClickListener ( v -> {
                String phone = getPhone ( );
                if ( TextUtils.isEmpty ( phone ) ) {
                    toast ( "请输入手机号" );
                    return;
                }
                String pwd = getPwd ( );
                if ( TextUtils.isEmpty ( pwd ) ) {
                    toast ( "请输入密码" );
                    return;
                }
                int sex;
                if ( view.rb1.isChecked ( ) ) {
                    sex = 1;
                } else if ( view.rb2.isChecked ( ) ) {
                    sex = 2;
                } else if ( view.rb3.isChecked ( ) ) {
                    sex = 3;
                } else {
                    sex = 0;
                }
                //调用注册接口
                presenter.register ( phone, pwd, sex );
            } );
        }
    
        private String getPhone ( ) {
            return view.edtPhone.getText ( ).toString ( );
        }
    
        private String getPwd ( ) {
            return view.edtPwd.getText ( ).toString ( );
        }
    }
    

    2. 用户模块(包含获取用户信息,更新用户信息(不做展示))

    2.1获取用户信息

    public class UserInfoActivity extends BaseActivity< ActivityUserInfoBinding > {
        @Override
        public ActivityUserInfoBinding setBaseView ( ) {
            return ActivityUserInfoBinding.inflate ( getLayoutInflater ( ) );
        }
    
        @Override
        public void onBaseCreate ( ) {
            IContractUser.IPresenterUserInfo presenterUserInfo=new PresenterUserInfo ( new IContractUser.IViewUserInfo ( ) {
                @Override
                public void onCallBack ( int i, boolean b, String s, UserInfo data ) {
                    if(b){
                        updateUi(data);
                    }else{
                        toast ( s );
                    }
                }
            } );
            addPresenter ( presenterUserInfo );
            presenterUserInfo.getInfo ();
        }
        private void updateUi(UserInfo info){
            //忽略更新ui的代码...
        }
    }
    

    重点:我该如何使用所谓的mcp?

    我们假设,你已经配置好了项目,那你就一应该这样做
    1.问后端的项目大佬拿到接口文档,去编写IBaseMode(rxjava)。
    2.新建契约类,契约类中就是你项目的所有需求,一般来讲可以一个模块对应一个契约类,契约类中再声明某个具体的功能。
    3.根据契约类新建各种Presenter。这里我建议这样,契约类的Presenter命名规范、明确一点,到时候新建实现类就复制粘贴就好。如契约类中声明IPresenterLogin,你就复制它,然后新建,直接粘贴“IPresenterLogin”,删掉“I”后,在PresenterLogin中直接implement IPresenterLogin,用快捷键就已经把契约类引入到你新建的类中了,然后那个Model不变,固定为“IBaseModel”,至于那个T(数据),连接到契约类就能拿到了。

    补充

    1.activity的基类请看这里:https://www.jianshu.com/p/4f28908ca603
    2.rxjava的解析工具请看这里:https://www.jianshu.com/p/d882ffae1853
    3.Retrofit2Managerd的代码,当你的项目有多个项目地址的时候,传入不同的url且用另一个IBaseModel接收就行。

    public class Retrofit2Manager {
        private long timeOut = 1000L * 20;
        private final String baseUrl;
    
        public static Retrofit2Manager with ( String baseUrl ) {
            return new Retrofit2Manager ( baseUrl );
        }
    
        private Retrofit2Manager ( String baseUrl ) {
            this.baseUrl = baseUrl;
        }
    
        public Retrofit2Manager setTimeOut ( long timeOut ) {
            this.timeOut = timeOut;
            return this;
        }
    
        public Retrofit retrofit ( ) {
            OkHttpClient.Builder okBuilder = new OkHttpClient.Builder ( );
            okBuilder.readTimeout ( this.timeOut, TimeUnit.MILLISECONDS );
            okBuilder.writeTimeout ( this.timeOut, TimeUnit.MILLISECONDS );
            okBuilder.connectTimeout ( this.timeOut, TimeUnit.MILLISECONDS );
            okBuilder.addInterceptor ( new LogInterceptor ( ) );
            return ( new retrofit2.Retrofit.Builder ( ) ).client ( okBuilder.build ( ) )
                    .baseUrl ( this.baseUrl )
                    .addConverterFactory ( MyConverterFactory.create ( ) )
                    .addCallAdapterFactory ( RxJava2CallAdapterFactory.create ( ) )
                    .build ( );
        }
    }
    

    总结

    1.总而言之,mcp是mvp在结合了rxjava之后,我自己总结出来的开发模式,在这种模式下,由接口到视图,逻辑严谨、清晰、合理而且相对简易。
    2.mcp直接将model层的逻辑设定为rxjava的逻辑,因此在代码量上,会少很多代码。对于presenter层,有了契约类,使用会更加方便。
    3.缺点:mcp模式下,依然撇不开mvp的毛病,就是presenter层的类太多太多,好在contract契约类可按模块管理presenter和view。

    以上就是小生对mvp和rxjava结合的总结,诸位大神有什么见解,欢迎提出来,一起学习,一起进步。

    相关文章

      网友评论

        本文标题:Android MVP开发模式与Rxjava+Retrofit结

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