Android MVP开发模式与Rxjava+Retrofit结合的使用

简述

直接起飞吧
本文章主要详细展示了安卓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.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 {
    /**
     * 设定类型
     *
     * @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 {
    /**
     * 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结合的使用)