RxJava2学习总结——操作符和应用场景

前言

2017年,刚毕业的我在项目组里打下手,组里其他人决定在新项目里使用RxJava,那时网络库用的是他们自己再次封装了的noHttp,加上了RxJava后,以前简单的网络请求多写了很多代码,这是我对RxJava的第一感受。
如今的项目基本上都是MVP+Retrofit2+Rxjava2的框架,但往往只是把Rxjava2和Retrofit2搭配进行网络请求而已,我也不例外。也曾看过好几次RxJava2的入门教程、操作符总结等,过段时间就忘了,而且不知在什么样的情景下适用恰当,所以写下这篇文章,打算带着问题出发,重新整理一下。
问题:
1、RxJava是什么,它优势是什么?
2、RxJava基础知识。
3、RxJava2操作符。
4、背压策略。
5、具体的使用场景。

1、RxJava是什么,它优势是什么?

RxJava官方介绍——一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。

Rxjava本质就是异步,它的优势是简洁。简洁是指相比于AsyncTask 、Handler、runOnUiThread等异步操作,RxJava的逻辑更简洁。一方面它是链式的,逻辑代码直观,二是它提供了很多强大的操作符。

2、RxJava基础知识

RxJava的基础知识,首先要知道它是用了可拓展的观察者模式,然后再了解这些概念,Observable、Observer、subscribe、处理事件、Scheduler。

1)什么是观察者模式?
观察者(Observer)不时刻盯着被观察者(Observable),而是通过注册(Register)或者称为订阅(Subscribe)的方式,告诉被观察者我需要你的某某状态,你要在它变化的时候通知我。
举例1:
A(观察者)和B(被观察者),A不需要每过 1s 就检查一次 B 的状态,而是B状态发生改变时,去通知A。
举例2:
View的点击事件,View(被观察者)->OnClickLisetener(观察者)->setOnClickListener(订阅)->OnClick(事件)。
举例3:
小偷在偷钱时告诉警察它要偷钱。小偷(被观察者)、警察(观察者)、小偷偷钱是某种状态、警察把小偷抓起来(事件)。

2)RxJava的观察者模式
Observable(被观察者)、Observer(观察者)、 subscribe(订阅)、事件。
看代码清楚明了,ObservableEmitter是事件发射器,在onSubscribe方法里可得到Disposable,可用于取消订阅。在观察者的方法体里有4个事件,解释看注释。如果发送了onError() 或 onComplete()事件,就取消了这个订阅。
一般用于网络请求时,都会写一个继承Observer的类来做处理,比如在onSubscribe()里做加载框显示,在onComplete()做某些共性判断,在onError()做统一失败处理等。所以Observer的4个方法肯定是要清楚的。

/**
* 打印结果:  只会打印1和2,3不打印
*/
Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            //ObservableEmitter类,事件发射器,作用是定义需要发送的事件 & 向观察者发送事件
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onComplete();
            emitter.onNext(3);
        }
    }).subscribe(new Observer<Integer>() {

        private Disposable mDisposable;  //用于取消订阅

        /**
         * 订阅成功就执行的方法
         * @param d  可切断操作
         */
        @Override
        public void onSubscribe(Disposable d) {
            mDisposable = d;
        }

        /**
         * 接收事件
         * @param integer
         */
        @Override
        public void onNext(Integer integer) {
            KLog.d(TAG, "onNext: " + integer + "\n");
        }

        /**
         * 失败,不再接收事件
         * @param e
         */
        @Override
        public void onError(Throwable e) {

        }

        /**
         * 完成,不再接收事件
         */
        @Override
        public void onComplete() {
        }
    });

3)线程控制Scheduler
Scheduler是线程调度,RxJava通过它来指定每一段代码运行在什么样的线程。例如网络请求用io流线程,更新UI就用mainThread,最常用也是这两个。
Schedulers.newThread():新线程。
Schedulers.io():在io()内部有线程池,可以使用空闲的线程,多数情况下比newThread()效率高。
Schedulers.computation():计算线程(没用过)。
AndroidSchedulers.mainThread():主线程。

4)取消订阅
RxJava2的取消订阅用Disposable.cancel(),如果订阅事件过多,要写管理类来管理。如果不取消订阅,就会造成内存泄漏,网上有RxLifecycle第三方库,可以很方便做取消订阅,它绑定了Activity or Fragment的生命周期。

3、RxJava2操作符

这里重新整理了一下当初学习的操作符,原本打算整理全部的操作符的,然后发现实在是太多了,就放弃了,下面的操作符绝大多数都来自于Android Rxjava:这是一篇 清晰 & 易懂的Rxjava 入门教程,想详细学习的可看这篇文章。网上也有很多文章有对操作符做简述,这篇文章比较完整Android拾萃 - RxJava2操作符汇总。最好结合代码学习,下载地址在本文最下面。

1)创建操作符
包括完整&快速创建被观察者,定时操作,周期性操作,数据/集合遍历

操作符 简述
基本创建
create() 普通创建,可以定义要发送的事件
快速创建
just() 快速创建一个Observable,最多发送10个参数
fromArray() 和just()类似,区别是传的是数组
fromIterable() 和fromArray()类似,区别是传入list集合
never() 不发送事件
empty() 仅发送complete事件
error() 仅发送empty事件
延迟创建
defer() 直到订阅才创建Observable
timer() 延迟一段时间再才发送
interval() 周期性发送,值从0开始递增。
intervalRange() 指定范围,周期性发送。可用于做验证码倒计时
range() 连续发送一个时间序列,可指定范围

2)变换操作符

操作符 简述
map() 将被观察者发送的事件转换为任意的类型事件。返回的是结果集,适用于一对一转换。(数据类型转换)
flatMap() 将被观察者发送的事件序列进行 拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送。返回的是包含结果集的Observable,适用于一对多,多对多得场景。
concatMap() 和flatMap()类似,区别是flatMap是无序的,concatMap是有序的,它的新事件序列和旧序列顺序一致。具体可以在flatMap生成事件的逻辑里加个延迟看到差异。
buffer() 定期从被观察者需要发送的事件中获取一定数量的事件,放到缓存区中,最终发送。两个参数,count是缓存区大小,skip是步长。
switchMap() 将Observable发射的数据集合变换为Observables集合,然后只发射这些Observables最近发射的数据
scan() 对Observable发射的每一项数据应用一个函数,然后按顺序依次发射每一个值
groupBy() 将Observable分拆为Observable集合,将原始Observable发射的数据按Key分组,每一个Observable发射一组不同的数据

3)组合/合并转换符

操作符 简述
组合多个被观察者
concat() / concatArray() 组合多个被观察者,按发送顺序串行执行。有Array是指传数组
merge()/mergeArray() 组合多个被观察者,按时间线并行执行
concatDelayError()/mergeDelayError() onError事件推迟到其他被观察者发送事件结束后才触发
合并多个事件
zip() 按数量合并,最终事件的数量=多个观察者中事件最少的数量。比如被观察者1有4个事件,被观察者2有5个事件,则组合起来事件数量是4。
combineLatest() 按时间合并,和最新事件合并。当两个Observable中的任何一个发送了事件后,将先发送了数据的Obervable的最新一个事件与另一个Observable发送的每个事件结合,最终基于该函数的结果发送事件。和zip的区别是,zip()按个数合并,1对1合并;combineLastest 按时间合并,在同一时间点上合并。
reduce() 把被观察者需要发送的事件聚合成1个事件
collect() 将被观察者Observable发送的数据事件收集到一个数据结构里
其他
startWith() 在一个被观察者发送事件前,追加发送一些数据 / 一个新的被观察者
count() 统计被观察者发送事件的数量

4)功能性操作符

操作符 简述
subscribe() 订阅,即连接观察者 & 被观察者
delay() 使得被观察者延迟一段时间再发送事件
doXXX() 各个事件操作符,如 doOnEach、doOnNext、doComplete等。
retry() 重试,即当出现错误时,让被观察者(Observable)重新发射数据
retryUntil() Observable遇到错误时,在retryUntil()的方法里决定,是否让Observable重新订阅
retryWhen() retryWhen将onError中的Throwable传递给一个函数,这个函数产生另一个Observable,由这个Observable来决定是否要重新订阅原Observable。
repeat() 无条件地、重复发送 被观察者事件
repeatWhen( int ) 传入参数 = 重复发送次数有限

5)过滤操作符

操作符 简述
filter() 过滤 特定条件的事件
ofType() 过滤 特定数据类型的数据
skip( int ) 跳过n个事件
skipLast( int ) 跳过最后的n个事件
distinct() 过滤事件序列中重复的事件
distinctUntilChanged() 只确保相邻元素不重复出现
take( int ) 指定只接收n个事件
takeLast( int ) 指定只接收最后发送的n个事件

6)条件/布尔操作符

操作符 简述
all() 判断发送的每项数据是否都满足设置的函数条件,若满足,返回 true;否则,返回 false。
takeWhile() 判断发送的每项数据是否满足设置函数条件,为true就发送,为false不发送,且终止发送事件(后面的事件也不发送了)。
skipWhile() 判断发送的每项数据是否满足设置函数条件,为true就不发送,为false发送,且终止发送事件。
takeUntil() 接收第一个Observable(调用takUtil的Observable)发送的数据,当第二个Observable(takUtil参数中的Observable)发送数据时,两个Obserable会同时取消订阅。
skipUntil() 与takeUtil()正好相反,不接收第一个Observable发送的数据,直到第二个Observable发送数据时才接收第一个Observable的数据,此时第二个Observable会取消订阅。
sequenceEqual() 判定两个Observables需要发送的数据是否相同,相同返回 true,不相同返回 false
contains() 判断发送的数据中是否包含指定数据。
isEmpty() 判断发送的数据是否为空
amb() 当需要发送多个 Observable时,只发送最先发送的Observable的数据,而其余Observable则被丢弃。

4.背压策略。

当在异步订阅中,通过Observable发射、处理、响应数据流时,如果事件产生的速度远远快于事件消费的速度,这些没来得及处理的数据就会越积越多,这些数据不会丢失,也不会被垃圾回收机制回收,而是存放在一个异步缓存池中,缓存池的数据一直得不到处理,最终会导致OOM等异常。这就是响应式编程中的背压问题。总结一下就是: 事件产生的速度大于事件消费的速度,数据堆积,最终造成OOM等异常。
RxJava2把对背压问题的处理逻辑从Observable中抽取出来产生了新的可观察对象Flowable,它是在Observable基础上做了优化,所以Observable能做的,它都能做,但是加了背压支持和其他的逻辑处理,它的效率比Observable慢得多,所以在需要用到背压的时候再用Flowable,其他时候还是正常使用Observable。网上找了两张图,可以很直观地看出RxJava1和2对背压的改动。


RxJava1.png

RxJava2.png

简单举个例子:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {

                //异步订阅时,代表的是 异步缓存池中可放入数据的数量,一开始是128,当产生10个事件而没有消费时,此时这个值是128-10=118。
                KLog.d(TAG, "异步缓存池中可放入数据的数量 = " + emitter.requested());

                // 一共发送4个事件
                KLog.d(TAG, "发送事件 1");
                emitter.onNext(1);
                KLog.d(TAG, "发送事件 2");
                emitter.onNext(2);
                KLog.d(TAG, "发送事件 3");
                emitter.onNext(3);
                KLog.d(TAG, "发送事件 4");
                emitter.onNext(4);
                KLog.d(TAG, "发送事件 onComplete()");
                emitter.onComplete();

                KLog.d(TAG, "异步缓存池中可放入数据的数量 = " + emitter.requested());

//                //模拟缓存超过128
//                for (int i = 0;i< 129; i++) {
//                    Log.d(TAG, "发送了事件" + i);
//                    emitter.onNext(i);
//                }
//                emitter.onComplete();
//
            }
        }, BackpressureStrategy.ERROR)  //缓存区超过128,直接抛出异常
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onSubscribe(Subscription s) {
                        // 在异步订阅情况下,一定要调用request,否则下流不接收事件
                        // 只接收多少个事件
                        s.request(3);
                    }

                    @Override
                    public void onNext(Integer integer) {
                        KLog.d(TAG, "接收到了事件" + integer);
                    }

                    @Override
                    public void onError(Throwable t) {
                        KLog.d(TAG, "onError:", t);
                    }

                    @Override
                    public void onComplete() {
                        KLog.d(TAG, "onComplete");
                    }
                });

可以看到Flowable和Subscriber的使用方式和之前的Observable和Observer极其类似,不同点如下:
1、create方法中多了一个BackpressureStrategy类型的参数。
2、Flowable发射数据时,使用FlowableEmitter,而Observable用的是ObservableEmitter。
3、Subscriber中,方法onSubscribe回调的参数不是Disposable而是Subscription。
下面对这三点进行说明。

BackpressureStrategy
缓存策略,也既是当缓存区存满、上流仍然继续发送下事件时,该如何处理的策略。默认缓存区大小是128(与Flowable的buffersize大小有关)。具体有哪些策略如下:
BackpressureStrategy.ERROR: 直接抛异常。
BackpressureStrategy.MISSING: 友好提示:缓存区满了。
BackpressureStrategy.BUFFER: 将缓存区设为无限大。
BackpressureStrategy.DROP: 超过缓存区大小128的事件丢弃。
BackpressureStrategy.LATEST: 只保存最后事件,超过缓存区大小128的事件丢弃。

Subscription
Subscription比Disposable多了一个方法request()。它的作用是告诉上游,下游需要多少数据,如果不设置request默认是0。比如设置为3,那么超过范围之外的数据就不接收了。如果多次调用request(),会累加。

FlowableEmitter
它比ObservableEmitter多了一个方法requested(),这个方法返回的是异步缓存池中可放入数据的数量,比如一开始是128,当产生10个事件而没有消费时,此时这个值是128-10=118。

Tips:不管Subscription.request(xx)设置了什么值,FlowableEmitter都会发送事件的,发送了不接收的就放入缓存里。背压在异步订阅中才有用,如果是同步订阅,是不会有缓存池的。

5.具体的使用场景

实际项目中,我只用来做过验证码倒计时、网络请求,RxBus。虽然了解了一些操作符,但网上的教程讲解这些操作符的时候都是以简单的例子来讲解的,具体的应用场景还是比较玄乎。

1)RxBus
EventBus是一个基于发布/订阅的事件总线,它简化了组件之间的通信操作。而这些RxBus都能做,所以用RxBus替换EventBus,在RxJava1就已经提出来了,如果自己的事件发送的要求不高,可以自己封装一个RxBus使用。17年的时候找的一篇文章 Android 用RxJava模拟一个EventBus ———RxBus,我在这基础上稍微改动了一下,但是没有做粘性事件。
原理简单来说就是找个容器装所有的观察者,当有某个事件产生时,找到所有需要这个事件的观察者,向它们发送事件。这个是否发送事件的依据,其实就是看观察者要什么样的class,比如订阅String类型的,那么Integer类型的事件就不会发给它。

两个新知识:
1)CompositeDisposable
一个disposable的容器,可以容纳多个disposable
2)Subject
Subject可以同时代表 Observer 和 Observable,允许从数据源中多次发送结果给多个观察者。

Subject 类别 简述
AsyncSubject 只有当 Subject 调用 onComplete 方法时,才会将 Subject 中的最后一个事件传递给所有的 Observer。
BehaviorSubject 当观察者订阅BehaviorSubject时,它开始发射原始Observable最近发射的数据(如果此时还没有收到任何数据,它会发射一个默认值),然后继续发射其它任何来自原始Observable的数据。然而,如果原始的Observable因为发生了一个错误而终止,BehaviorSubject将不会发射任何数据,只是简单的向前传递这个错误通知。Rxlifecycle2库用的就是这个。
PublishSubject 不会改变事件的发送顺序,在已经发送了一部分事件之后注册的 Observer 不会收到之前发送的事件。RxBus用的这个。
ReplaySubject 无论什么时候注册 Observer 都可以接收到任何时候通过该 Observable 发射的事件。 RxBus粘性事件可用这个。
UnicastSubject 只允许一个 Observer 进行监听,在该 Observer 注册之前会将发射的所有的事件放进一个队列中, 并在 Observer 注册的时候一起通知给它。
public class RxBus {

    /**
     * CompositeDisposable定义:
     * 一个disposable的容器,可以容纳多个disposable,添加和去除的复杂度为O(1)
     *
     * 此处使用目的:
     * 是为了一个订阅者能够对应多个Disposable,在需要的时候调用 Disposable 的 dispose()取消订阅。
     *
     * 举个例子:
     * XXActivity,订阅了事件A和事件B,关闭时要取消订阅。
     * 那么只需在mSubscriptionMap里找到key为XXActivity的Value(CompositeDisposable),再取出Disposable
     * 取消订阅即可。
     *
     * 如果不用的话,就要为每一个Activity写一个容器去保存它的订阅的事件了。
     * */
    private HashMap<String, CompositeDisposable> mSubscriptionMap;
    private static volatile RxBus mRxBus;
    private final Subject<Object> mSubject;

    public static RxBus getIntanceBus(){
        if (mRxBus==null){
            synchronized (RxBus.class){
                if(mRxBus==null){
                    mRxBus = new RxBus();
                }
            }
        }
        return mRxBus;
    }

    
    /**
     * 正常订阅可用PublishSubject、黏性事件可用ReplaySubject。
     */
    private RxBus(){
        mSubject = PublishSubject.create().toSerialized();
    }

    /**
     * 一个默认的订阅方法
     * @param <T>
     * @param type   过滤,只返回特定数据类型的数据
     * @param next   next()事件,正常接收的事件
     * @param error  error()事件,错误接收的事件
     * @return
     */
    public <T> Disposable doSubscribe(Class<T> type, Consumer<T> next, Consumer<Throwable> error){
        return getObservable(type)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(next,error);
    }

    /**
     * 返回指定类型的带背压的Flowable实例
     * 这里选定背压模式是 BackpressureStrategy.BUFFER,缓存区无限大
     * @param <T>
     * @param type  过滤,只返回特定数据类型的数据
     * @return
     */
    public <T> Flowable<T> getObservable(Class<T> type){
        return mSubject.toFlowable(BackpressureStrategy.BUFFER).ofType(type);
    }

    /**
     * 发送事件
     * @param o 事件
     */
    public void post(Object o){
        mSubject.onNext(o);
    }


    /**
     * 判断是否已有观察者订阅
     *
     * @return
     */
    public boolean hasObservers() {
        return mSubject.hasObservers();
    }

    /**
     * 保存订阅后的disposable,取消订阅的时候要用
     * @param o       订阅的目标
     * @param disposable
     */
    public void addSubscription(Object o, Disposable disposable) {
        if (mSubscriptionMap == null) {
            mSubscriptionMap = new HashMap<>();
        }
        //这里key值取订阅目标的实体名称(com.xx.xx.xxx),不是底层类检称
        String key = o.getClass().getName();
        //disposable 放到对应的 CompositeDisposable 里
        if (mSubscriptionMap.get(key) != null) {
            mSubscriptionMap.get(key).add(disposable);
        } else {
            CompositeDisposable disposables = new CompositeDisposable();
            disposables.add(disposable);
            mSubscriptionMap.put(key, disposables);
        }
    }

    /**
     * 取消订阅
     * @param o
     */
    public void unSubscribe(Object o) {
        if (mSubscriptionMap == null) {
            return;
        }
        String key = o.getClass().getName();
        if (!mSubscriptionMap.containsKey(key)){
            return;
        }
        if (mSubscriptionMap.get(key) != null) {
            mSubscriptionMap.get(key).dispose();
        }
        mSubscriptionMap.remove(key);
    }

    /********************************* 为RxEventBean 封装  **********************************/
    /**
     * 使用EventBus时,为了方便查找,一般都会封装 EventBean(int code,Object content)
     * 但是所有的订阅者都是订阅的这个类型,所以要自己做判断做类型转换。
     *
     * 这里写死事件是RxEventBean,且错误处理一般不处理,只用处理onNext即可。
     * @param context
     * @param action
     * */
    public void register(Context context, Consumer<RxEventBean> action) {
        Disposable disposable = RxBus.getIntanceBus().doSubscribe(RxEventBean.class, action,
                throwable -> KLog.e("RxEventBean onError()", throwable.toString()));
        RxBus.getIntanceBus().addSubscription(context,disposable);
    }


    /**
     * 发送RxEventBean 事件
     * @param code     code,用于判断
     * @param content  内容,接收后做类型转换
     */
    public void post(int code, Object content){
        RxEventBean<Object> event = new RxEventBean<>();
        event.code = code;
        event.content = content;
        post(event);
    }
}

2)验证码倒计时
其实关键代码就是用intervalRange()操作符。

public class RxCodeHelper {

    private Context mContext;
    private TextView codeBt;
    private Disposable mDisposable;

    /**
     * 构造函数
     * @param mContext 上下文
     * @param codeBt   验证码的button
     */
    public RxCodeHelper(Context mContext, TextView codeBt) {
        this.mContext = mContext;
        this.codeBt = codeBt;
    }

    /**
     * 开启倒计时
     */
    public void start(){
        codeBt.setEnabled(false);
        //从0开始,走60个数,延迟是0s,周期为1次。
        Observable.intervalRange(0,60,0,1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        mDisposable = d;
                    }

                    @Override
                    public void onNext(Long aLong) {
                        codeBt.setText((60 - aLong) + "s后可重发");
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {
                        //倒计时完毕置为可点击状态
                        codeBt.setEnabled(true);
                        codeBt.setText("获取验证码");
                    }
                });
    }

    /**
     * 请求失败时,重置状态
     * 取消倒计时的订阅事件
     */
    public void reset(){
        if(mDisposable!=null){
            mDisposable.dispose();
        }
        codeBt.setEnabled(true);
        codeBt.setText("获取验证码");
    }

    /**
     * 界面销毁时,取消倒计时订阅事件
     */
    public void stop(){
        if(mDisposable!=null){
            mDisposable.dispose();
        }
    }

}

3)RxLifecycle
目的:解决RxJava的内存泄漏问题。
用法:
bindUntilEvent(@NonNull ActivityEvent event)——绑定指定的生命周期,在指定生命周期时取消订阅。
bindToLifecycle() ——绑定生命周期,取消订阅策略可看源码。以Activity为例,可看RxLifecycleAndroid 下的 ACTIVITY_LIFECYCLE, 实际上在onCreate()订阅的,在onDestroy()取消订阅;在onResume()订阅的,在onPause()取消订阅。

知识点:
compose():
将一种类型的Observable转换成另一种类型的Observable,保证调用的链式结构。
LifecycleTransformer:
LifecycleTransformer实现了各种Transformer接口,能够将一个Observable/Flowable/Single/Completable/Maybe对象转换成另一个 Observable/Flowable/Single/Completable/Maybe对象。正好配合上文的compose操作符,使用在链式调用中。

举例在网络请求时绑定生命周期,mvp模式。
Activity继承了RxFragmentActivity后,BaseView接口里新增两个方法,其他View层接口继承它。

public interface BaseView {
//为了让 IView 可以调用 RxLifeCycle的生命周期绑定
<T> LifecycleTransformer<T> bindToLifecycle();
<T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event);
}

在P层使用,此处模拟网络请求,3s后回调

Observable.timer(3, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io()) //订阅在io线程
.observeOn(AndroidSchedulers.mainThread()) //回调在主线程
.compose(mView.bindUntilEvent(ActivityEvent.DESTROY)) //指定在onDestroy销毁
// .compose(mView.bindToLifecycle()) //取消订阅交由RxLifeCycle来判断
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(Disposable d) {
mView.showLoading();
}

@Override
public void onNext(Long aLong) {
KLog.d("onTest1Success()回调成功");
mView.onTest1Success("onTest1 请求成功");
}

@Override
public void onError(Throwable e) {
mView.dismissLoading();
}

@Override
public void onComplete() {
mView.dismissLoading();
}
});

一般使用,可以用compose封装一下,如下:

/**
     * 统一线程处理,且绑定生命周期
     * 用法: xxx .compose(RxUtil.rxSchedulerHelper(mView))
     * @param view
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T,T> rxSchedulerHelper(BaseView view){
        return new ObservableTransformer<T,T>() {
            @Override
            public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
                return upstream
                        .subscribeOn(Schedulers.io())    //订阅在io线程
                        .unsubscribeOn(Schedulers.io())  //取消订阅在io线程,为啥要这个,不太清楚
                        .observeOn(AndroidSchedulers.mainThread()) //回调在主线程
                        .compose(view.bindToLifecycle());  //绑定生命周期
            }
        };
    }

结尾

在网上找了一些操作符的简单例子和应用场景,写了一个Demo,看操作符概述的时候,结合代码运行结果来看更容易理解,有兴趣的可以看看。后续会在这个项目里继续更新操作符和应用场景。
Github地址:
https://github.com/Dengszzzzz/DRxJavaSummary

参考

给 Android 开发者的 RxJava 详解
这可能是最好的RxJava 2.x 入门教程
Android拾萃 - RxJava2操作符汇总
Rxjava2入门教程五:Flowable背压支持——对Flowable最全面而详细的讲解
Android Rxjava:这是一篇 清晰 & 易懂的Rxjava 入门教程
实际应用场景
Android 用RxJava模拟一个EventBus ———RxBus
RxLifecycle详细解析
...

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容

  • RxJava RxJava是响应式程序设计的一种实现。在响应式程序设计中,当数据到达的时候,消费者做出响应。响应式...
    Mr槑阅读 928评论 0 5
  • 本文首发于“随手记技术团队”公众号 大概从2015年开始,RxJava1.0开始快速流行起来,短短两年时间,RxJ...
    HolenZhou阅读 2,149评论 0 19
  • 目录 一:创建操作 二:合并操作 三:过滤操作 四:切换线程 五:条件/布尔操作 六:聚合操作 七:转换操作 八:...
    Allens_Jiang阅读 10,049评论 11 32
  • RxJava2.0的使用详解 1,初识RxJava RxJava就是一种用Java语言实现的响应式编程,来创建基于...
    CarlosLynn阅读 2,835评论 0 0
  • 一、Retrofit详解 ·Retrofit的官网地址为 : http://square.github.io/re...
    余生_d630阅读 1,801评论 0 5