美文网首页Rxjava的学习Android 入门进阶RxJava
RxJava2 + Retrofit2 优雅简洁封装

RxJava2 + Retrofit2 优雅简洁封装

作者: 此人丶不用抒情 | 来源:发表于2017-02-09 20:02 被阅读22391次

    RxJava2 封装主要变化

    • Transformer的变化:RxJava1.X为rx.Observable.Transformer接口, 继承自Func1<Observable<T>, Observable<R>>, RxJava2.X为io.reactivex.ObservableTransformer<Upstream, Downstream>,是一个独立的接口。
    • Flowable则是FlowableTransformer,如果你使用Flowable,以下ObservableTransformer替换FlowableTransformer即可。

    gitHub 项目地址

    RxJava2 + Retrofit2.jpg

    封装方案

    1、封装 Rx 线程相关

    RxSchedulersHelper:

    /**
     * Created by weiss on 17/1/16.
     */
    public class RxSchedulers {
        public static <T> ObservableTransformer<T, T> io_main() {
            return upstream ->
                    upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread());
        }
    }
    

    封装后:

    Api.getInstance().movieService
                    .getGankData("Android",1)
                    .compose(RxSchedulers.io_main());
    

    2、封装 处理服务器返回数据,管理 RxJava生命周期

    HttpResult:

    /**
     * Created by Weiss on 2017/1/11.
     */
    
    public class HttpResult<T> implements Serializable {
        public String code;
        public String msg;
        public boolean hasmore;
        public T data;
    
        public static String SUCCESS = "000";
        public static String SIGN_OUT = "101";//token验证失败
        public static String SHOWTOAST = "102";//显示Toast
    
        public boolean isSuccess() {
            return SUCCESS.equals(code);
        }
    
        public boolean isTokenInvalid() {
            return SIGN_OUT.equals(code);
        }
    
        public boolean isShowToast() {
            return SHOWTOAST.equals(code);
        }
    
        public boolean hasMore() {
            return hasmore;
        }
    }
    

    BaseRxActivity:

    
    /**
     * 管理RxJava生命周期,避免内存泄漏
     * RxJava处理服务器返回
     *
     * Created by Weiss on 2016/12/23.
     */
    
    public abstract class BaseRxActivity extends BaseActivity {
    
        private CompositeDisposable disposables2Stop;// 管理Stop取消订阅者者
        private CompositeDisposable disposables2Destroy;// 管理Destroy取消订阅者者
    
        protected abstract int getLayoutId();
    
        protected abstract void initView();
    
        /**
         * Rx优雅处理服务器返回
         *
         * @param <T>
         * @return
         */
        public <T> ObservableTransformer<HttpResult<T>, T> handleResult() {
            return upstream ->{
                    return upstream.flatMap(result -> {
                                if (result.isSuccess()) {
                                    return createData(result.data);
                                } else if (result.isTokenInvalid()) {
                                    //处理token失效,tokenInvalid方法在BaseActivity 实现
                                     tokenInvalid();
                                } else {
                                    return Observable.error(new Exception(result.msg));
                                }
                                return Observable.empty();
                            }
    
                    );
            };
        }
    
        private <T> Observable<T> createData(final T t) {
            return Observable.create(subscriber -> {
                try {
                    subscriber.onNext(t);
                    subscriber.onComplete();
                } catch (Exception e) {
                    subscriber.onError(e);
                }
            });
        }
    
        public boolean addRxStop(Disposable disposable) {
            if (disposables2Stop == null) {
                throw new IllegalStateException(
                        "addUtilStop should be called between onStart and onStop");
            }
            disposables2Stop.add(disposable);
            return true;
        }
    
        public boolean addRxDestroy(Disposable disposable) {
            if (disposables2Destroy == null) {
                throw new IllegalStateException(
                        "addUtilDestroy should be called between onCreate and onDestroy");
            }
            disposables2Destroy.add(disposable);
            return true;
        }
    
        public void remove(Disposable disposable) {
            if (disposables2Stop == null && disposables2Destroy == null) {
                throw new IllegalStateException("remove should not be called after onDestroy");
            }
            if (disposables2Stop != null) {
                disposables2Stop.remove(disposable);
            }
            if (disposables2Destroy != null) {
                disposables2Destroy.remove(disposable);
            }
        }
    
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if (disposables2Destroy != null) {
                throw new IllegalStateException("onCreate called multiple times");
            }
            disposables2Destroy = new CompositeDisposable();
        }
    
        public void onStart() {
            super.onStart();
            if (disposables2Stop != null) {
                throw new IllegalStateException("onStart called multiple times");
            }
            disposables2Stop = new CompositeDisposable();
        }
    
        public void onStop() {
            super.onStop();
            if (disposables2Stop == null) {
                throw new IllegalStateException("onStop called multiple times or onStart not called");
            }
            disposables2Stop.dispose();
            disposables2Stop = null;
        }
    
        public void onDestroy() {
            super.onDestroy();
            if (disposables2Destroy == null) {
                throw new IllegalStateException(
                        "onDestroy called multiple times or onCreate not called");
            }
            disposables2Destroy.dispose();
            disposables2Destroy = null;
        }
    }
    

    封装后 (BaseRxActivity的子类使用):

    addRxDestroy(Api.getInstance().movieService
                    .getGankData("Android",1)
                    .compose(RxSchedulers.io_main())
                    .compose(handleResult())
                    .省略
    );
    

    handleResult为什么不新建一个类处理呢?因为很多异常处理需要context对象,或者和BaseActivity有千丝万缕的联系,BaseRxActivity继承BaseActivity可以很简洁优雅处理各种异常。比如token失效,是需要跳转到登录页面的。在新建一个类中,不能持有context对象,只能使用Application的Context,同时方便与Activity通信交互满足各种需求。BaseRxActivity还可以管理RxJava生命周期。

    3、异常处理

    
    /**
     * Created by Weiss on 2017/2/9.
     */
    
    public class RxException<T extends Throwable> implements Consumer<T> {
    
        private static final String TAG = "RxException";
    
        private static final String SOCKETTIMEOUTEXCEPTION = "网络连接超时,请检查您的网络状态,稍后重试";
        private static final String CONNECTEXCEPTION = "网络连接异常,请检查您的网络状态";
        private static final String UNKNOWNHOSTEXCEPTION = "网络异常,请检查您的网络状态";
    
        private Consumer<? super Throwable> onError;
        public RxException(Consumer<? super Throwable> onError) {
            this.onError=onError;
        }
    
        /**
         * Consume the given value.
         *
         * @param t the value
         * @throws Exception on error
         */
        @Override
        public void accept(T t) throws Exception {
            if (t instanceof SocketTimeoutException) {
                Log.e(TAG, "onError: SocketTimeoutException----" + SOCKETTIMEOUTEXCEPTION);
                ToastUtils.show(SOCKETTIMEOUTEXCEPTION);
                onError.accept(new Throwable(SOCKETTIMEOUTEXCEPTION));
            } else if (t instanceof ConnectException) {
                Log.e(TAG, "onError: ConnectException-----" + CONNECTEXCEPTION);
                ToastUtils.show(CONNECTEXCEPTION);
                onError.accept(new Throwable(CONNECTEXCEPTION));
            } else if (t instanceof UnknownHostException) {
                Log.e(TAG, "onError: UnknownHostException-----" + UNKNOWNHOSTEXCEPTION);
                ToastUtils.show(UNKNOWNHOSTEXCEPTION);
                onError.accept(new Throwable(UNKNOWNHOSTEXCEPTION));
            } else {
                Log.e(TAG, "onError:----" + t.getMessage());
                onError.accept(t);
            }
        }
    }
    

    封装后 (BaseRxActivity的子类使用):

    addRxDestroy(Api.getInstance().movieService
                    .getGankData("Android",1)
                    .compose(RxSchedulers.io_main())
                    .compose(handleResult())
                    .subscribe(httpResult -> adapter.setItems(data),
                                    new RxException<>(e ->e.printStackTrace()))
    );
    

    4、多页请求封装

    实体类:

    /**
     * Created by Weiss on 2017/1/20.
     */
    
    public class Gank extends BaseListEntity {
        @Override
        public Observable<HttpResult<List<Gank>>> getPage(int page) {
            return GankApi.getInstance().service.getGankData(param.get("gank"), page)
                    .compose(RxSchedulers.io_main());
        }
    
    }
    

    实体类继承 BaseListEntity,实现getPage方法即可。

    UI视图:

    public class MainActivityFragment extends BaseRxFragment {
        @BindView(R.id.ptrRecyclerView)
        PtrRecyclerView ptrRecyclerView;
    
        private MultiTypeAdapter adapter;
    
        public MainActivityFragment() {
        }
    
    
        @Override
        protected int getLayoutId() {
            return R.layout.fragment_main;
        }
    
        @Override
        protected void initView() {
            ptrRecyclerView.setParam("gank","Android");
            adapter = new MultiTypeAdapter();
            adapter.register(Gank.class,new GankViewProvider());
            ptrRecyclerView.setAdapter(adapter,new Gank());
        }
    }
    
    

    只需要写一个适配器和实体类,轻松实现多页请求,PtrRecyclerView下拉刷新和上拉加载是会自动调用getPage()方法获取数据。
    PtrRecyclerView目前只是简单实现下拉刷新和上拉加载,有空会完善,当然例子也会完善。当然PtrRecyclerView的封装会根据RecyclerView原生的方法名参数,减少学习成本。

    后记

    还可以封装网络加载对话框,这个看个人喜好,同样以上封装同样可以看个人喜好和项目需求自由组装。
    RxJava2 + Retrofit2 封装 giithub 源码地址

    相关链接

    RxJava 2.0有什么不同(译)
    探索专为 Android 而设计的 RxJava 2
    RxJava2 + Retrofit2 开发框架

    相关文章

      网友评论

      • 84b94bc62bd9:为什么我的onError和onNext同时都调用了,我只是添加了一个请求头而已,就不行了
      • 岛在深海处:没搞懂为什么BaseRxActivity中要包装2个CompositeDisposable,既然stop()已经dispose()了为什么还要再onDestroy()中去dispose()?
        此人丶不用抒情:因为有些需求是要在stop()去dispose(),有些是要在onDestroy()去dispose()
      • BKQ_SYC:你这个有处理网络缓存吗?
      • wan7451:取消订阅完全没有调用啊
      • 空老表:在实际应用中发现,rx2.0不支持空值的传递,剥离Result 的时候,如果value返回值为null则不能走正常的回调,请问楼主这一块是怎么解决的呢
        空老表: @木子it 不通过rx剥离外层数据,在回调的时候自己封装一下,值传递就可以传null了
        木子it: 我也遇到,你有解决吗?
      • 准备流浪的雪:还会调用retrofit2里面的callback吗,401,404,之类的怎么处理呢
      • afe0c4c1d3c1:楼主:内存这块能不能优化下
        此人丶不用抒情:主要是Demo的图片缓存,设置Glide的最大缓存就行了
      • afe0c4c1d3c1:学习了 正在找这方面的资料
      • Jerome_0a49:lz 你用的rxJava版本是多少,我用ObservableTransformer转换器那里,发现以前用的方法那里没有抛出exception ,现在2.0.7版本做了异常处理,是否直接可以将结果返回,如
        完整:
        public static <T> ObservableTransformer<ResultData<T>, T> obsTransformer() {
        return upstream -> upstream.flatMap(new Function<ResultData<T>, ObservableSource<T>>() {

        @Override
        public ObservableSource<T> apply(@NonNull ResultData<T> tResultData) throws Exception {
        return Observable.just(tResultData.getData());
        }
        });
        }
      • 王元_Trump:里面的jni那个部分 什么意义呢
        此人丶不用抒情: @王元_Trump 没有意义,刚开始是想写NDK教程,晚上我删除这部分😁
      • 王元_Trump:学习一下
      • 大步大步向前走:文章更新了?昨晚看的时候没有github项目地址。现在学习了,第一次看见异常处理不打断lambda 的封装,看起来更简洁优雅。多页请求,M 层实现getPage的思路,也值得学习:grin:
        此人丶不用抒情: @大步大步向前走 写完文章才赶出demo,下次写博客会注意的,等内容完善才发布。

      本文标题:RxJava2 + Retrofit2 优雅简洁封装

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