1、概述
RxJava是一个著名的开源库,是ReactiveX(Reactive Extensions)的一种java实现。ReactiveX是一种响应式扩展框架,有很多实现,如RxAndroid,RxJS,RxSwift,RxRuby,RxCpp,RxGo等。RxJava有1.x和2.x两个主要的分支,分别代表着RxJava1和RxJava2。
RxJava可以看作由Observable,Subscriber和Scheduler组成,它们关系图为
Subscriber订阅到Observable,Observable会在默认或者指定的Scheduler上工作并产生数据流返回给Subscriber,Subscriber也会在默认或者在指定的Scheduler上接收Observable要送过来的数据流。Scheduler是对线程的抽象,不同的Scheduler代表了不同的线程
1.1 Observable和Subscriber
Observable提供了subscribe方法,当有Subscriber通过subscribe方法订阅到Observable时,Observable可以向Scheduler发送数据流。响应式编程中的事件分为三类:普通事件、错误事件和结束事件。在Subscriber中有三个方法与这三种事件一一对应。Observable会通过调用Subscriber的这三个方法发送对应的事件。
- onNext:当Observable要发送普通事件时,就会调用这个方法,可以被调用0-N次
- onError:当在Observable内部有异常或者错误产生的时候,可以调用这个方法来向Subscriber发送错误事件,这个方法只能被调用1次。
- onComplete:如果Observable已经发送完所有的数据,并且没有发生错误,这时需要 调用 这个方法来向Subscriber发送结束事件,这个方法也只能调用1次,而且和onError是互斥关系。
Subscriber提供了unsubscribe方法,当Subscriber订阅到Observable之后,可随时调用这个方法来终止对Observable的订阅。
除了通用的Observable之外,还有两种特殊的Observable,分别是Single和Completable,与之分别对应的Subscriber是SingleSubscriber和CompletableSubscriber。
2、操作符
2.1 创建操作符
range | 创建的Observable会发送一个范围内的数据 |
defer | 只有当Subscriber来订阅的时候才会创建一个新的Observable对象 |
just | 接收某个对象作为输入 ,然后再创建一个发送该对象的Observable |
from | 接收一个对象作为参数来创建Observable,可以是Iterable,Callable,Future。just操作符创建的Observable会将整个参数对象一次性发送出去。而使用from创建的Observable会每次只发送一次。 |
interval | 创建的Observable对象会从0或者初始延时时间开始,每隔固定的时间发送一个数字。这个对象是运行在Scheduler中。 |
repeat | 让Observable对象发送的数据重复发送N次,可以指定其发送的次数 |
timer | 创建的Observable会在指定时间后发送一个数字0,默认是运行在computation Scheduler上 |
2.2 转换操作符
buffer | 将数据按照规定的大小做一下缓存,当缓存的数据量达到设置的上限后就将缓存的数据作为一个集合发送出去。可以设置跳过的数目。不仅可以通过数量规则来缓存,也可以通过时间规则来缓存 |
flatMap | 将Observable转化为多个以源Observable发送的数据作为源数据的Observable,然后将这多个Observable发送的数据整合并发送出来。还有一个扩展操作符flatMapIterable |
groupBy | 将源Observable发送的数据按照key来拆分成一些小的Observable,然后这些小的Observable分别发送其所包含的数据 |
map | 将源Observable发送的每个数据都按照给定的函数进行转化,并将转化后的数据发送出来。 |
cast | 将Observable发送的数据强制转化为另外一种类型。 |
scan | 对一个序列的数据应用同一个函数进行计算,并将这个函数的结果发送出去,作为下一个数据应用这个函数时的第一个参数使用。 |
2.3 过滤操作符
debounce | 用来做限流的 |
throttleWithTimeout | 通过时间来限流 |
distinct | 用于去重 |
elementAt | 只会过滤出源Observable发送出来的顺序为N的数据。 |
filter | 根据一个函数来进行过滤操作。源Observable发送的数据作为参数传递到函数里,如果函数的返回值为true,则这个数据将继续被发送出去,否则数据将会被过滤掉。 |
first | 只会返回第一条或者满足条件的第一条数据 |
last | 只返回最后一条或者满足条件的最后一条数据 |
skip | 将源Observable发送的数据过滤掉前n项。 |
take | 只取前n项 |
skipLast | 从后面操作过滤到n项 |
takeLast | 从后面操作取n项 |
sample | 指定一段时长,在每段时长结束的时候发送源Observable发送的最新数据,其他的都会被过滤掉。 |
throttleFirst | 取的是在规定时间段内的第一个数据,其他的会被过滤掉 |
2.4 组合操作符
combineLatest | 将2-9个Observable发送的数组组合起来,再发送出来。有两个前提:所有组合的Observable都发送过数据;任何一个Observable发送一个数据,combineLatest就将所有Observable最新发送的数据按照提供的函数组装起来发送出去。 |
join | 根据时间窗口来组合两个Observable发送的数据 |
groupJoin | 与join相似,只是发送出来的是一个个小的Observable,每个Observable里面包含了一轮组合数据。 |
merge | 将多个Observable发送的数据整合起来发送。当某一个Observable发出onError时,merge的过程会被停止并将错误分发给Subscriber。 |
mergeDelayError | 会在merge结束后再分发错误 |
zip | 将多个Observable发送的数据按顺序组合起来。 |
2.5 错误处理操作符
onErrorReturn | 在发生错误时,让Observable发送一个预先定义好的数据并停止 继续发送数据,正常结束整个过程 |
onErrorResumeNext | 在有错误事件的时候会创建另外一个Observable来代替当前的Observable并继续发送数据。 |
onExceptionResumeNext | 与onErrorResumeNext类似,会对onError抛出的数据类型做判断,如果是Exception,就会使用另外一个Observable代替原Observable继续发送数据,否则会将错误分发给Subscriber |
retry | 在发生错误时会重新进行订阅,而且可以重复多次,所以发送的数据可能会产生重复,但是有可能每次retry都会发生错误,从而造成不断订阅不断retry的死循环,可以指定最大重复次数。 |
2.6 辅助操作符
delay | 让发送数据的时机延后一段时间,所有数据都会依次延后一段时间再发送。 |
delaySubscription | 延时注册Subscriber |
do系列 | 给Observable的生命周期的各个阶段加上一系列的回调监听,当Observable执行到这个阶段的时候,这些回调就会被触发。 doOnEach:Observable每发送一个数据的时候就会触发这个回调,无论Observable调用 的是onNext,onError还是onCompleted doOnNext:只有Observable调用onNext发送数据的时候才会被触发 doOnSubscribe和doOnUnsubscribe:会在Subscriber进行订阅和反订阅的时候触发回调。当一个Observable通过onError或者onCompleted结束的时候,会反订阅所有的Subscriber doOnError:会在Observable通过OnError分发错误事件的时候触发回调,并将Throwable对象作为参数传进回调函数里。 doOnComplete:会在Observable通过OnCompleted发送结束事件的时候触发回调。 doOnTerminate:会在Observable结束前触发回调,无论是正常结束还是异常结束 finallyDo:会在Observable结束后触发回调,无论时正常结束还是异常结束。 |
materialize | 将OnNext,OnError和OnComplete事件都转化为一个Notification对象并按照原来的顺序发送出来。 |
dematerialize | 执行相反的过程,将这些Notification对象重新转化成对应的OnNext,OnError和OnComplete事件。 |
subscribeOn | 指定Observable在哪个线程上运行 |
observeOn | 指定观察者所运行的线程,也就是发送出的数据在哪个线程上使用。 |
timeInterval | 拦截源Observable发送出来的数据,将其封装为一个TimeInterval对象 |
timeStamp | 将每个数据项重新包装成一个TimeStamp对象。 |
timeout | 给Observable加上超时时间,每发送一个数据后就重置计时器,当超过预定的时间还没有发送下一个数据时,就抛出一个超时的异常。 |
using | 创建一个在Observable生命周期内存活的资源 |
2.7 条件操作
all | 根据一个函数对源Observable发送的所有数据进行判断,最终返回的结果是这个判断结果。 |
amb | 可以将至多9个Observable结合起来,哪个Observable首先发送了数据(包括onError和onComplete),就继续发送这个Observable数据,其他Observable所发送的数据都会被丢弃。 |
contains | 判断源Observable所发送的所有数据是否包含某一个数据,如果包含返回true,如果源Observable已经结束了却还没有发送这个数据,返回false |
isEmpty | 判断源Observable是否发送数据,如果发送过就会返回false,如果源Observable已经结束了都还没有发送这个数据,返回true |
defaultIfEmpty | 判断源Observable是否发送了数据,如果源Observable发送了数据则正常发送这些数据,否则发送一个默认的数据。 |
sequenceEqual | 判断两个 Observable发送的数据序列是否相同。 |
skipUntil | 根据一个标志Observable来判断的,当这个标志Observable没有发送数据的时候,所有源Observable发送的数据都会被跳过。当标志Observable发送了一个数据后,则开始正常地发送数据 |
skipWhile | 根据一个函数来判断是否跳过数据,如果函数返回值为true,则一直跳过源Observable发送的数据;如果函数返回false,则开始正常发送数据。 |
takeUntil | 与skipUntil功能相反。 |
takeWhile | 与skipWhile功能相反 |
2.8 聚合操作符
concat | 将多个Observable结合成一个Observable并发送数据,并且严格按照先后顺序发送数据。 |
count | 用来统计源Observable发送了多少个数据,最后将数目发送出来。 |
reduce | 应用一个函数接收Observable发送的数据和函数的计算结果,作为下次计算的参数,并输出最后的结果。 |
collect | 与reduce类似,将源Observable发送的数据收集到一个数据结构里面,最后将这个数据结构整个发送出来。 |
2.9 与Connectable Observable相关操作符
publish | 将普通的Observable转化为Connectable Observable |
connect | 用来触发Connectable Observable发送数据。应用connec操作符后会返回一个Subsciption对象,通过这个Subscription对象,可以调用其unsubscribe方法来中止数据的发送。 |
refCount | 将一个Connectable Observable对象再重新转化为一个普通的Observable对象。 |
replay | 返回一个Connectable Observable对象并且可以缓存其发送的数据 |
2.10 自定义操作符
需要遵守以下几条规则
- 自定义操作符在发送任何数据之前都要使用 subscriber.isUnsubscribed()来检查Subscriber的状态,如果没有任何Subscriber订阅就没有必要去发送数据了。
- 自定义操作要遵循Observable的核心原则
- 可以多次调用Subscriber的onNext方法,但是同一个数据只能调用一次。
- 可以调用Subscriber的onComplete或者onError方法,但这两个方法是互斥的。
- 如果无法保证遵守以上两条原则,可以对自定义操作符加上serialize操作符,这个操作符会强制发送正常的数据。
- 自定义操作符内部不能阻塞住
- 如果通过组合多个RxJava原生的操作符就能达到目的,就不要使用自定义操作符来实现。
lift | 可以实现一个自定义的操作符。 |
compose | 需要 创建一个实现了Transformer接口的对象。 |
3、Scheduler
3.1 类型
有computation, io,newThread等类型。
computation Scheduler:适用于和CPU相关的任务,不适合那些会阻塞的任务。
newThread Scheduler:每次都会新建一个线程,一般情况下不推荐使用这个,因为创建一个线程都会造成稍微的延迟。
io Scheduler:类似于newThread Scheduler,io Scheduler可以被回收利用。内部会维持一个线程池,当使用io Scheduler来处理任务的时候 ,会首先从线程池中查找空闲的线程,如果有空闲线程就会在这个空闲线程上执行任务,否则会创建一个新的线程来执行任务,并在任务执行完毕时将这个空闲的线程放入到线程池中。当然空闲的线程不会一直在那里等待,RxJava默认空闲线程的存活时间是60秒,空闲时间超过60秒的线程会被回收。适合那些使用很少CPU资源的I/O操作。
immediate Scheduler:会在当前的线程上立即开始执行任务,这会将当前线程正在进行的任务阻塞。
trampoline Scheduler:与immediate Scheduler相似,在当前线程上执行任务,不是立即开始执行任务的,而是等待当前线程上之前的任务都结束之后再开始执行。
3.2 类抽象
3.3 类层次图
4、RxJava实现原理
4.1 订阅
调用Observable的subscribe方法,会调用另一个静态subscribe方法将Observable自身作为一个参数传入。
static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
// validate and proceed
if (subscriber == null) {
throw new IllegalArgumentException("subscriber can not be null");
}
if (observable.onSubscribe == null) {
throw new IllegalStateException("onSubscribe function can not be null.");
/*
* the subscribe function can also be overridden but generally that's not the appropriate approach
* so I won't mention that in the exception
*/
}
// new Subscriber so onStart it
subscriber.onStart();
/*
* See https://github.com/ReactiveX/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls
* to user code from within an Observer"
*/
// if not already wrapped
if (!(subscriber instanceof SafeSubscriber)) {
// assign to `observer` so we return the protected version
subscriber = new SafeSubscriber<T>(subscriber);
}
// The code below is exactly the same an unsafeSubscribe but not used because it would
// add a significant depth to already huge call stacks.
try {
// allow the hook to intercept and/or decorate
RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber);
return RxJavaHooks.onObservableReturn(subscriber);
} catch (Throwable e) {
// special handling for certain Throwable/Error/Exception types
Exceptions.throwIfFatal(e);
// in case the subscriber can't listen to exceptions anymore
if (subscriber.isUnsubscribed()) {
RxJavaHooks.onError(RxJavaHooks.onObservableError(e));
} else {
// if an unhandled error occurs executing the onSubscribe we will propagate it
try {
subscriber.onError(RxJavaHooks.onObservableError(e));
} catch (Throwable e2) {
Exceptions.throwIfFatal(e2);
// if this happens it means the onError itself failed (perhaps an invalid function implementation)
// so we are unable to propagate the error correctly and will just throw
RuntimeException r = new OnErrorFailedException("Error occurred attempting to subscribe [" + e.getMessage() + "] and then again while trying to pass to onError.", e2);
// TODO could the hook be the cause of the error in the on error handling.
RxJavaHooks.onObservableError(r);
// TODO why aren't we throwing the hook's return value.
throw r; // NOPMD
}
}
return Subscriptions.unsubscribed();
}
}
订阅时序图为
订阅的过程就是调用 Observable内部的成员变量onSubscribe的call方法,将Subscriber作为参数传入进去,然后由onSubscribe对象向Subscriber发送数据的过程。在不使用Scheduler时,Observable和Subscriber都会运行在订阅时的线程上。
4.2 操作符实现
4.2.1 lift工作原理
OnSubscribeLift类结构
创建Observable时序
lift订阅时的时序
创建一个liftObservable,liftObservable的onSubscribe成员变量是一个OnSubscribeLift对象,该对象持有一个Observable的onSubscribe成员变量的引用。当有Subscriber订阅的时候会调用这个OnSubscribeLift对象的call方法,调用Operator的call方法返回一个包装后的Subscriber对象,然后再调用源onSubscribe的call方法将liftSubscriber 传进去。源Observable在发送数据时,会先发送到liftSubscriber,由liftSubscriber对数据做一些自定义的操作,然后再发送给原始的Subscriber.
4.2.2 map工作原理
类结构为:
依赖于OnSubscribeMap类,并且会将当前的Observable对象和Func1对象一起作为构造函数,然后创建并返回一个新的Observable,称之为MapObservable。
订阅时序图为
订阅时调用call方法会做如下操作
- 创建一个新的MapSubscriber:parent
- 将parent通过add方法添加到源Subscriber中,这样在取消订阅时能够将所有Subscriber都取消
- 将parent订阅到源Observable中。
4.2.3 flatMap工作原理
首先判断一下当前的Observable是否是ScalarSynchronousObservable。普通的Observable是先map然后再merge。
通过map结合传入的Func1对象将源Observable发送的数据转化为一个个小的Observable,然后通过merge将所有小的Observable组合成一个Observable后返回 。
OperateMerge类结构
OperatorMerge操作符作用时创建MergeSubscriber,包含了源Subscriber。
当MergeSubscribe接收到数据时,创建InnerSubscriber,同时让接收到的数据Observable订阅InnserSubscriber。同时启动发送数据emit。将数据发送给源Subscriber
InnserSubscriber接收到数据时,会调用MergeSubscriber的tryEmit将数据发送给源Subscriber
其处理图为
4.2.4 concat工作原理
其方法为
其类结构图为
订阅时序图为
5、Subject
PublishSubject:接收订阅之后的所有数据
ReplaySubject:接收订阅前后的所有数据
BehaviorSubject:接收订阅前的最近一个及订阅后的所有数据
AsyncSubject:只接收最后一条数据
6、BlockingObservable
转换成Future通过使用BlockingOperatorToFuture操作符
public static <T> Future<T> toFuture(Observable<? extends T> that) {
final CountDownLatch finished = new CountDownLatch(1);
final AtomicReference<T> value = new AtomicReference<T>();
final AtomicReference<Throwable> error = new AtomicReference<Throwable>();
@SuppressWarnings("unchecked")
final Subscription s = ((Observable<T>)that).single().subscribe(new Subscriber<T>() {
@Override
public void onCompleted() {
finished.countDown();
}
@Override
public void onError(Throwable e) {
error.compareAndSet(null, e);
finished.countDown();
}
@Override
public void onNext(T v) {
// "single" guarantees there is only one "onNext"
value.set(v);
}
});
return new Future<T>() {
private volatile boolean cancelled;
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (finished.getCount() > 0) {
cancelled = true;
s.unsubscribe();
// release the latch (a race condition may have already released it by now)
finished.countDown();
return true;
} else {
// can't cancel
return false;
}
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public boolean isDone() {
return finished.getCount() == 0;
}
@Override
public T get() throws InterruptedException, ExecutionException {
finished.await();
return getValue();
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (finished.await(timeout, unit)) {
return getValue();
} else {
throw new TimeoutException("Timed out after " + unit.toMillis(timeout) + "ms waiting for underlying Observable.");
}
}
private T getValue() throws ExecutionException {
final Throwable throwable = error.get();
if (throwable != null) {
throw new ExecutionException("Observable onError", throwable);
} else if (cancelled) {
// Contract of Future.get() requires us to throw this:
throw new CancellationException("Subscription unsubscribed");
} else {
return value.get();
}
}
};
}
使用CountDownLatch来实现,源Observable订阅特定的Subscriber,在处理onNext时,设置返回结果,在处理onComplete时,countDownLatch减1,在处理onError时设置error值,同时countDownLatch减1结束。在future中获取值时,等待countDownLatch
参考资料: