zoukankan      html  css  js  c++  java
  • 一时兴起的MVP+RxJava+Retrofit的封装录

    MVP介绍:

    MVP 全称:Model-View-Presenter ;MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

    RxJava介绍:

    RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。对RxJava不熟悉的可以看下https://gank.io/post/560e15be2dca930e00da1083这篇文章(我也不是很熟悉,拿来就用而已,手动摊手)。

    Retrofit介绍:

    Retrofit 其实相当简单,简单到源码只有37个文件,其中22个文件是注解还都和HTTP有关,真正暴露给用户的类并不多,所以我看了一遍 官方教程 大多数情景就可以无障碍使用,如果你还没有看过,可以先去看看,虽然是英文,但代码才是最好的教程不是么?当然本篇文章会介绍得详细一点,不能写一篇水文,毕竟我给它命名为《你真的会用Retrofit2吗?Retrofit2完全教程》。附上链接 https://www.jianshu.com/p/308f3c54abdd
     
    进入正题吧,我们首先来尝试搭建一个MVP框架:
    1、从View开始,新建一个BaseView接口,定义一下View层通用的方法;
    public interface BaseView {
        /**
         * 显示正在加载view
         */
        void showLoading();
        /**
         * 关闭正在加载view
         */
        void hideLoading();
        /**
         * 显示提示
         * @param msg
         */
        void showToast(String msg, int length);
        /**
         * 显示请求错误提示
         */
        void showErr(String errMsg);
        /**
         * 获取上下文
         * @return 上下文
         */
        Context getContext();
    }

    比如现在有个登录需求需要实现,新建一个LoginView,并继承BaseView,使各功能View能自行实现自己的需求;

    public interface LoginView extends BaseView {
    
        void loginSuccess();
    
        void loginFailure();
    
    }

    OK,我们现在有了登录模块的View了,那么,我们可以在相关登录模块的Activitiy,Fragment上实现该LoginView,例如:

    public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView{
        @Override
        public void loginSuccess() { } 
    
        @Override 
        public void loginFailure() { } 
    }

    好的,那么我们的LoginActivity就实现了我们的LoginView功能了,BaseActivity待会会介绍;

    View大概就这么多,可以根据具体的功能需求添加删除;

    2、Presenter层:由上文提到的,负责逻辑处理;

    同样,新建一个BasePresenter类,因为presenter层级的操作是基于View层的,我们需要在BasePresenter每一步操作前判断我们的view是否存在;

    public class BasePresenter<V extends BaseView> {
    
        private V view;
    
        /**
         * 绑定view,一般在初始化中调用该方法
         */
        public void attachView(V view){
            this.view = view;
        }
    
        /**
         * 断开view,一般在onDestroy中调用
         */
        public void detachView(){
            this.view = null;
        }
    
        /**
         * 是否与View建立连接
         * 每次调用业务请求的时候都要出先调用方法检查是否与View建立连接
         */
        public boolean isViewAttached(){
            return view != null;
        }
    
        /**
         * 获取连接的view
         */
        public V getView(){
            return this.view;
        }
    
        public Context getContext(){
            return this.view.getContext();
        }
    
    }

    如上图,我们可以通过isViewAttached判断view是否存在,如果view已销毁,我们的逻辑处理也没必要继续下去,进行相对应的销毁工作即可;

    OK,同样我们来实现功能Presenter,按照View的现在,我们也实现一个登录模块的Presenter,新建一个LoginPresenter抽象类,并将对应的View以泛型参数声明:

    public abstract class LoginPresenter extends BasePresenter<LoginView> {
    
        /**
         * 登录方法
         */
        public abstract void login(String phoneNum, String password);
    
    }

    然后,我们将具体实现LoginPresenter,新建一个LoginPresenterImpl类,并继承LoginPresenter;

    public class LoginPresenterImpl extends LoginPresenter {
    
        @Override
        public void login(String phoneNum, String password) {
            if (isViewAttached()) {
                // 实现Login功能
            }
        }
    }

    Ok,现在我们回头来看LoginActivity,将我们对应功能Presenter以泛型参数传入

    LoginActivity extends BaseActivity<LoginPresenter>

    3、来看看BaseActivity,直接上代码:

    public abstract class BaseActivity<T extends BasePresenter> extends FragmentActivity implements BaseView {
    
        protected T mPresenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setupContentView();
            initView();
            createPresenterAndAttachView();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (mPresenter != null) {
                mPresenter.detachView();
            }
        }
    
        @Override
        public void showLoading() {
            Views.getInstance().showTipDialog(Views.TIPDIALOG_LOADING, this);
        }
    
        @Override
        public void hideLoading() {
            Views.getInstance().closeTipDialog();
        }
    
        @Override
        public void showToast(String msg, int length) {
            runOnUiThread(() -> Toast.makeText(getContext(), msg, length).show());
        }
    
        @Override
        public void showErr(String errMsg) {
            showToast(errMsg, Toast.LENGTH_LONG);
        }
    
        @Override
        public Context getContext() {
            return BaseActivity.this;
        }
    
        protected abstract void createPresenterAndAttachView();
    
        protected abstract void setupContentView();
    
        protected abstract void initView();
    }

    BaseActivity实现BaseView,将公共功能实现一下,同时我们的Presenter在onDestroy()上将view解绑,同时我也写了几个抽象方法,createPresenterAndAttachView()在该方法中创建Presenter并进行view的连接工作,

    其他就可有可无啦,根据自己的想法走吧。

    好了,我们现在差不多可以用起来了。来看看LoginActivity的具体实现:

    public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView, View.OnClickListener {
    
        @Override
        protected void createPresenterAndAttachView() {
            // 实例化Presenter
            mPresenter = new LoginPresenterImpl();
            // view建立连接
            mPresenter.attachView(this);
        }
    
        @Override
        protected void setupContentView() {
            setContentView(R.layout.activity_login);
        }
    
        @Override
        protected void initView() {
            // 初始化界面
        }
    
        @Override
        public void loginSuccess() {
            // 登录成功
        }
    
        @Override
        public void loginFailure() {
            // 登录失败
        }
    
        @Override
        public void onClick(View view) {
    
        }
    }
        

    4、上面似乎还少了个Model层,Model层主要是负责数据,如网络访问,数据库查询等操作,该层没有进一步进行封装了,先来看看Presenter层里是怎样跟Model层交互的;

    public class LoginPresenterImpl extends LoginPresenter {
    
        @Override
        public void login(String phoneNum, String password) {
            if (isViewAttached()) {
                Map<String, Object> params = new HashMap<>();
                params.put("phoneNum", phoneNum);
                params.put("password", password);
                UserModel.login(getContext(), params, new Callback<LoginResponse>() {
                    @Override
                    public void onSuccess(LoginResponse data) {
    
                    }
    
                    @Override
                    public void onFailure(int errCode, String msg) {
    
                    }
                });
            }
        }
    
    }

    如上图,在Presenter具体的逻辑实现中,我们只是简单的调用了Model层进行具体的数据操作;

    让我们看看UserModel是怎样做的:

    /**
     * 用户Model
     */
    public final class UserModel {
    
        /**
         * 登录
         * @param params
         * @param callback
         */
        public static void login(Context context, Map<String, Object> params, Callback<LoginResponse> callback) {
            RetrofitManager.getInstance().createService(UserApi.class).login(params)
                    .compose(RetrofitManager.getInstance().ioMainSchedulers())
                    .subscribe(new BaseObserver<>(context, callback));
        }
    }

    LoginResponse是服务端返回的实体数据,具体如何造就看你服务端具体返回什么了;

    Callback是一个通用的接口,如下:

    public interface Callback<T> {
    
        /**
         * 数据请求成功
         *
         * @param data
         */
        void onSuccess(T data);
    
        /**
         * 使用网络API接口请求方式时,虽然已经请求成功但是由
         * 于{@code msg}的原因无法正常返回数据。
         */
        void onFailure(int errCode, String msg);
    }

    5、终于到RxJava和Retrofit的使用了,RetrofitManager是一个Retrofit管理类

    /**
     * Retrofit管理类
     */
    public final class RetrofitManager {
    
    
        private Retrofit retrofit;
    
        public static RetrofitManager getInstance() {
            return RetrofitHelper.manager;
        }
    
        private RetrofitManager() {
            retrofit = new Retrofit.Builder()
                    .baseUrl(HttpConstants.BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
        }
    
        private static class RetrofitHelper {
            private static final RetrofitManager manager = new RetrofitManager();
        }
    
        public <T> T createService(Class<T> clazz) {
            return retrofit.create(clazz);
        }
    
        public <T> ObservableTransformer<T, T> ioMainSchedulers() {
            return upstream -> upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
        }
    }

    主要就是实现一个单例模式,然后配合RxJava进行使用,如下login接口:

    public interface UserApi {
    
        @FormUrlEncoded
        @POST(HttpConstants.LOGIN)
        Observable<BaseResponse<LoginResponse>> login(@FieldMap Map<String, Object> params);
    }

    Retrofit+RxJava主要是接口返回参数为RxJava的Observable,就是这么简单,深入的我也还没去研究,先用起来吧。

    Ok,大概就是这样了。这样的话,我们的各层级进行了应有的解耦,代码也干净了很多。但是,代码量我觉得是多了的。

    自己随手记录的一些内容,相当于是复习了下RxJava,Retrofit的使用和Mvp的概念,不喜勿喷。

  • 相关阅读:
    浅谈js的继承
    Android调用jni全过程,方便以后操作
    oracle中查找执行效率低下的SQL
    EBS R12 怎么修改APPS密码
    oracle查看系统资源占用情况
    ramfs
    091104 晴
    周六
    注意调整
    短信收到
  • 原文地址:https://www.cnblogs.com/Jhon-Mr/p/9628828.html
Copyright © 2011-2022 走看看