RxJava是是一个基于事件流处理来实现异步操作的库。对于需要切换线程来异步处理的场景,能够简化代码编写,提高代码可读性。官网地址: ReactiveX
被观察者负责生产事件,观察者负责处理事件,一旦观察者 订阅了 被观察者,就会触发被观察者发送事件流。这里的“事件”是一个抽象概念,它的载体是一个数据结构(例如String/Object/自定义对象等),传递的实际上是数据,只是在观察者模式中它们的角色是“事件”。事件流对应的,是要传递的数据流。
RxJava使用基于事件流的链式调用,事件“从上游流向下游”,中间可以多次做各种处理和变换,最终流到最下游被处理掉。最初的被观察者是事件流的源头,而观察者位于事件流的最下游。
大致可分为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中既可以配置被观察者生产/发送事件执行的线程,也可以配置观察者处理事件的线程,因此可以支持实现异步操作。
当不做任何线程调度配置时,默认二者都会在当前线程中执行,此时被观察者、观察者是同步执行的,发送一个事件、处理一个事件,然后继续进行下一轮发送和处理。
当配置二者不在同一线程执行时,事件的发送和处理是异步的,被观察者将事件发送到对应的“事件缓冲区”,然后观察者从事件缓冲区取事件来处理。
异步处理时,有可能观察者处理事件较慢,而被观察者发送事件较快,则事件不停在 “事件缓冲区”堆积。 “事件缓冲区” 默认最多缓冲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个事件时,会额外保存一个事件,只会额外保存最新发送的这个事件。
当通过继承自 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() { }
});
通过subscribeOn()方法指定被观察者生产事件的线程,可指定多次,则只有第一次指定有效。通过 observeO()指定观察者处理事件的线程,可指定多次,每次指定均有效,每指定一次,就会切换一次线程。(RxJava是通过内部的 Schedulers调度器来实现线程切换的。)
//设置被观察者生产和发送事件在IO线程执行
flowable.subscribeOn(Schedulers.io())
//设置观察者处理事件在Android主线程执行
.observeOn(AndroidSchedulers.mainThread());
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
|
类型
|
作用
|
map()
|
1个源事件变换出一个结果事件,后继发送顺序不变
|
FlatMap()
|
源事件与结果事件对应关系随意,后继发送顺序随机
|
ConcatMap()
|
源事件与结果事件对应关系随意,后继发送顺序按照与源事件关系来排列
|
Buffer()
|
设置一个数量和步长,每轮从被观察者发送的事件集合中取指定数量发送到下游,下一轮按照步长移动后,依旧发送指定数量,不断重复此步骤知道全部发送完。
|
/**
* map示例
*/
flowable.map(new Function() {
@Override
public Character apply(String s) throws Throwable {
//此处将事件类型String处理成Character,发送到下游
return s.charAt(0);
}
});
类型 |
作用 |
delay() |
延迟指定时间发送事件 |
doOnEach() doOnNext() doAfterNext() doOnError() doOnSubscribe() doOnComplete() doAfterTerminate() doFinally() |
每当对应类型事件处理前或处理后后,都会执行执行方法 |
onErrorReturn() onErrorResumeNext() onExceptionResumeNext() |
出现错误或异常时,拦截并触发函数内的逻辑,最后发送onComplete()。 前两者异常和错误都拦截;第三个操作方法只拦截异常,不拦截会触发onError()的场景,并且最终不调用onComplete()。 |
retry() retryWhen() |
出错时重试 |
repeat() repeatWhen() |
不断重复发送事件 |