RxJava使用总结

##.简介

    RxJava是是一个基于事件流处理来实现异步操作的库。对于需要切换线程来异步处理的场景,能够简化代码编写,提高代码可读性。官网地址: ReactiveX

一、使用流程概括和示例

1.它是按照观察者模式来设计的

    被观察者负责生产事件,观察者负责处理事件,一旦观察者 订阅了 被观察者,就会触发被观察者发送事件流。
    这里的“事件”是一个抽象概念,它的载体是一个数据结构(例如String/Object/自定义对象等),传递的实际上是数据,只是在观察者模式中它们的角色是“事件”。事件流对应的,是要传递的数据流。
    RxJava使用基于事件流的链式调用,事件“从上游流向下游”,中间可以多次做各种处理和变换,最终流到最下游被处理掉。最初的被观察者是事件流的源头,而观察者位于事件流的最下游。
RxJava使用总结_第1张图片

2.使用流程和示例

大致可分为3步:
1)创建被观察者,编写事件生产和发送逻辑;
    通过事件发射器 FlowableEmitter的onNext()/onComplete()/onError()等来传递事件。
2)创建观察者,编写事件处理逻辑;
    通过自己的 onNext()/onComplete()/onError()等来接受事件并处理。
    注意:上游事件发送正常结束时 onComplete()被调用, onError()在出错时被调用,二者出现时都意味着事件流处理结束,但二者只会有一个被调用到。
3)观察者 订阅 被观察者,触发 被观察者生产和发送时间,然后观察者接收事件并处理。
代码示例和注释讲解:
/**
* 1.创建被观察者
* 有多种创建方式,这是其中较常见一种,通过Create()方法创建
* 第二个参数是背压策略
*/
Flowable flowable = Flowable.create(new FlowableOnSubscribe() {
    /**
     * 被订阅后,会触发调用该方法
     * @param emitter   事件发射器,可通过它将事件传递给观察者
     * @throws Throwable
     */
    @Override
    public void subscribe(@NonNull FlowableEmitter emitter) throws Throwable {
        //通过onNext()方法来传递事件(数据)
        emitter.onNext("aaa");
        emitter.onNext("bbb");
        emitter.onNext("ccc”);
        //调用onComplete(),意味着事件流发送已结束
        //后面再调用onNext()也不会再将事件发送出去
        emitter.onComplete();
    }
}, BackpressureStrategy.ERROR);

/**
* 2.创建观察者
*/
FlowableSubscriber flowableSubscriber = new FlowableSubscriber() {
    /**
     * 一旦订阅,会首先调用该方法
     * 传入的参数s是Subscription类型,对应的是"订阅"这个抽象概念
     * 通过调用Subscription.cancel()可以取消订阅,停止事件流发送和接收
     * @param s
     */
    @Override
    public void onSubscribe(@NonNull Subscription s) {

    }

    /**
     * 通过该方法将数据传递过来
     * @param s
     */
    @Override
    public void onNext(String s) {
        //.....处理数据.....
    }

    /**
     * 当出错时,该方法会被调用,事件流传递会结束掉。
     * onError()和onComplete()只会有一个被调用到。
     * @param t
     */
    @Override
    public void onError(Throwable t) {

    }

    /**
     * 该方法被调用,意味着事件流传递已结束
     * onError()和onComplete()只会有一个被调用到。
     */
    @Override
    public void onComplete() {

    }
};

/**
* 3.订阅
* 订阅后,首先会触发观察者执行onSubscribe()方法
* 然后会触发被观察者执行FlowableOnSubscribe.subscribe()内的逻辑,
*      观察者可在此方法中写生产事件和发射的逻辑,最终事件会在观察者的回调方法中被处理
*/
flowable.subscribe(flowableSubscriber);
习惯上会把以上步骤串在一起链式调用,这样写起来、读起来都更简便:
/**
* 习惯上会把以上步骤串在一起写,这些写起来、读起来都更简便
*/
Flowable.create(new FlowableOnSubscribe() {
    //被订阅后,会触发调用该方法
    @Override
    public void subscribe(@NonNull FlowableEmitter emitter) throws Throwable {
        //通过onNext()方法来传递事件(数据)
        emitter.onNext("aaa");
        emitter.onNext("bbb");
        emitter.onNext("ccc");
        //调用onComplete(),意味着事件流发送已结束
        //后面再调用onNext()也不会再将事件发送出去
        emitter.onComplete();
    }
}, BackpressureStrategy.ERROR)
        //设置被观察者生产和发送事件在IO线程执行
        .subscribeOn(Schedulers.io())
        //设置观察者处理事件在主线程执行
        .observeOn(AndroidSchedulers.mainThread())
        //订阅
        .subscribe(new FlowableSubscriber() {
            @Override
            public void onSubscribe(@NonNull Subscription s) {
                //一旦订阅,会首先调用该方法
            }

            @Override
            public void onNext(String s) {
                //.....处理数据.....
            }

            @Override
            public void onError(Throwable t) {

            }

            @Override
            public void onComplete() {

            }
        });

二.异步处理相关

    RxJava中既可以配置被观察者生产/发送事件执行的线程,也可以配置观察者处理事件的线程,因此可以支持实现异步操作。

1.同步处理

    当不做任何线程调度配置时,默认二者都会在当前线程中执行,此时被观察者、观察者是同步执行的,发送一个事件、处理一个事件,然后继续进行下一轮发送和处理。

2.异步处理    

    当配置二者不在同一线程执行时,事件的发送和处理是异步的,被观察者将事件发送到对应的“事件缓冲区”,然后观察者从事件缓冲区取事件来处理。

3.背压策略

    异步处理时,有可能观察者处理事件较慢,而被观察者发送事件较快,则事件不停在 “事件缓冲区”堆积。 “事件缓冲区” 默认最多缓冲128个事件,一旦超出就会报错。所以需要一种策略来处理这种情况,缓解上游过快的事件流带来的压力,所以叫“背压策略”。
背压策略是针对缓冲区的策略,除了采用背压策略外,针对该问题,也可以通过其它方案解决:控制上游发送事件速度、或者让下游放弃处理部分事件。)
背压策略有:
3.1 BackpressureStrategy.ERROR:
    默认使用的背压策略,缓存量超出128个就触发onError(),传递异常 MissingBackpressureException
3.2 BackpressureStrategy.MISSING:
    跟 BackpressureStrategy.ERROR类似,onError()传递的信息中多了句提示内容。
3.3  BackpressureStrategy.BUFFER:
    将缓冲区设置为无限大,此时倒是不会报错了,但是事件如果一直在缓冲区累积下去,容易出现OOM问题。
3.4  BackpressureStrategy.DROP:
    缓存超过128个事件时,新发送的事件会被丢弃掉。
3.5  BackpressureStrategy.LATEST
    缓存超过128个事件时,会额外保存一个事件,只会额外保存最新发送的这个事件。

4.观察者设置可接收的事件数量

    当通过继承自 FlowableSubscriber 接口的方法自定义观察者对象时, 必须通过Subscription.request(long n)方法来设置允许接收的事件数量, 被观察者发送事件的数量也不能超过这个数量,否则会抛异常。 /可多次调用该方法,允许接收的事件数量是每次调用值的总和,如下例,允许:发送30=10+20个事件。 如果使用的是DisposableSubscriber, 则其onSubscribe()已经调用了Subscription.request(Long.MAX_VALUE),不需要再额外设置。
    被观察者可通过FlowableEmitter.requested()获取观察者设置的事件发送数量,  每次调用,获取到的都是当前剩余可发送的事件数量。 当减到0时,则代表观察者已经不可接收事件, 此时继续发送事件,会抛出MissingBackpressureException异常。    
Flowable.create(new FlowableOnSubscribe() {
    //被订阅后,会触发调用该方法
    @Override
    public void subscribe(@NonNull FlowableEmitter emitter) throws Throwable {
        //被观察者可通过FlowableEmitter.requested()获取观察者设置的事件发送数量,
        //  每次调用,获取到的都是当前剩余可发送的事件数量。
        //当减到0时,则代表观察者已经不可接收事件,
        //  此时继续发送事件,会抛出MissingBackpressureException异常
        long size = emitter.requested();
        for(int i = 0; i < size; i++){
            emitter.onNext("order"+i);
        }
        emitter.onComplete();
    }
}, BackpressureStrategy.ERROR)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        //订阅
        .subscribe(new FlowableSubscriber() {
            //一旦订阅,会首先调用该方法
            @Override
            public void onSubscribe(@NonNull Subscription s) {
                //必须通过Subscription.request(long n)方法来设置允许接收的事件数量,
                //      被观察者发送事件的数量不能超过这个数量,否则会抛异常
                //可多次调用该方法,允许接收的事件数量是每次调用值的总和,如下例,允许:发送30=10+20个事件
                //如果使用的是DisposableSubscriber,
                //  则其onSubscribe()已经调用了Subscription.request(Long.MAX_VALUE)
                s.request(10);
                s.request(20);
            }
            @Override
            public void onNext(String s) { }
            @Override
            public void onError(Throwable t) { }
            @Override
            public void onComplete() { }
        });

5.配置被观察者、观察者的执行线程

5.1配置方法

    通过subscribeOn()方法指定被观察者生产事件的线程,可指定多次,则只有第一次指定有效。
    通过 observeO()指定观察者处理事件的线程,可指定多次,每次指定均有效,每指定一次,就会切换一次线程。
    (RxJava是通过内部的 Schedulers调度器来实现线程切换的。)
示例:
        //设置被观察者生产和发送事件在IO线程执行
flowable.subscribeOn(Schedulers.io())
        //设置观察者处理事件在Android主线程执行
        .observeOn(AndroidSchedulers.mainThread());

5.2 RxJava内置线程类型

RxJava中内置了多种用于调度的线程类型。 RxJava使用线程池来维护这些线程,所以又较高调度效率。

类型

对应线程

一般应用场景

Schedulers.trampoline() 在当前线程上执行

默认设置,如果不额外指定线程,默认会在被观察者创建线程执行

AndroidSchedulers.mainThread()

Android主线程

操作UI

Schedulers.newThread()

常规新线程

耗时等操作

Schedulers.io()

IO操作线程

(做了一定优化适配IO操作)

网络请求、读写文件等IO操作密集、有异步阻塞、数据缓冲的操作

Schedulers.computation()

CPU计算操作线程

用于处理有大量计算的操作

Schedulers.single()

对应于一个共享的单例调度器实例,指向一个默认的单线程

如果需要多个任务在同一后台上执行时,可以配置为此线程

Schedulers.from(Executor)    

使用指定的Executor作为调度器

可以自己编写Executor的execute()逻辑,来自定义调度逻辑


三、被观察者类型
类型
描述
Observable
能够发射0或n个数据,并以成功或错误事件终止。
Flowable
能够发射0或n个数据,并以成功或错误事件终止。 支持Backpressure背压策略(事件缓冲区应对事件堆积过多时的策略)。
Single
只发射单个数据或错误事件。
Completable
它从来不发射数据,只处理 onComplete 和 onError 事件。可以看成是Rx的Runnable。
Maybe
能够发射0或者1个数据,要么成功,要么失败。有点类似于Optional

四、各种操作符

1.创建操作符:用于创建被观察者和事件

RxJava使用总结_第2张图片

2.变换操作符:对于事件用指定函数处理后,将结果作为事件继续发送到下游

类型
作用
map()
1个源事件变换出一个结果事件,后继发送顺序不变
FlatMap()
源事件与结果事件对应关系随意,后继发送顺序随机
ConcatMap()
源事件与结果事件对应关系随意,后继发送顺序按照与源事件关系来排列
Buffer()
设置一个数量和步长,每轮从被观察者发送的事件集合中取指定数量发送到下游,下一轮按照步长移动后,依旧发送指定数量,不断重复此步骤知道全部发送完。
示例:
/**
* map示例
*/
flowable.map(new Function() {
    @Override
    public Character apply(String s) throws Throwable {
        //此处将事件类型String处理成Character,发送到下游
        return s.charAt(0);
    }
});

3.条件判断、过滤操作符:用于根据判断条件筛选出/过滤掉部分事件

RxJava使用总结_第3张图片
RxJava使用总结_第4张图片

4.组合 / 合并操作符:用于合并多个被观察者事件序列

5.功能操作符

类型

作用

delay()

延迟指定时间发送事件

doOnEach()

doOnNext()

doAfterNext()

doOnError()

doOnSubscribe()

doOnComplete()

doAfterTerminate()

doFinally()  

每当对应类型事件处理前或处理后后,都会执行执行方法

onErrorReturn()

onErrorResumeNext()

onExceptionResumeNext()

出现错误或异常时,拦截并触发函数内的逻辑,最后发送onComplete()。

前两者异常和错误都拦截;第三个操作方法只拦截异常,不拦截会触发onError()的场景,并且最终不调用onComplete()。

retry()

retryWhen()

出错时重试

repeat()

repeatWhen()

不断重复发送事件

(声明:部分图片来自网络,侵删!)

你可能感兴趣的:(Android网络相关,android,RxJava,线程调度,观察者模型,RxJava操作符)