runAsync
rxjava-async
模块还包含一个runAsync
操作符。它很特殊,返回一个叫做StoppableObservable
的特殊Observable。
传递一个Action
和一个Scheduler
给runAsync
,它返回一个使用这个Action
产生数据的StoppableObservable
。这个Action
接受一个Observable
和一个Subscription
作为参数,它使用Subscription
检查unsubscribed
条件,一旦发现条件为真就立即停止发射数据。在任何时候你都可以使用unsubscribe
方法手动停止一个StoppableObservable
(这会同时取消订阅与这个StoppableObservable
关联的Subscription
)。
由于runAsync
会立即调用Action
并开始发射数据,在你创建StoppableObservable之后到你的观察者准备好接受数据之前这段时间里,可能会有一部分数据会丢失。如果这不符合你的要求,可以使用runAsync
的一个变体,它也接受一个Subject
参数,传递一个ReplaySubject
给它,你可以获取其它丢失的数据了。
在RxJava中还有一个版本的From
操作符可以将Future转换为Observable,与start
相似。
Timer
创建一个Observable,它在一个给定的延迟后发射一个特殊的值。
Timer
操作符创建一个在给定的时间段之后返回一个特殊值的Observable。
RxJava将这个操作符实现为timer
函数。
timer
返回一个Observable,它在延迟一段给定的时间后发射一个简单的数字0。
timer
操作符默认在computation
调度器上执行。有一个变体可以通过可选参数指定Scheduler。
- Javadoc: timer(long,TimeUnit)
- Javadoc: timer(long,TimeUnit,Scheduler)
变换操作
这个页面展示了可用于对Observable发射的数据执行变换操作的各种操作符。
- map( ) — 对序列的每一项都应用一个函数来变换Observable发射的数据序列
- flatMap( ), concatMap( ), and flatMapIterable( ) — 将Observable发射的数据集合变换为Observables集合,然后将这些Observable发射的数据平坦化的放进一个单独的Observable
- switchMap( ) — 将Observable发射的数据集合变换为Observables集合,然后只发射这些Observables最近发射的数据
- scan( ) — 对Observable发射的每一项数据应用一个函数,然后按顺序依次发射每一个值
- groupBy( ) — 将Observable分拆为Observable集合,将原始Observable发射的数据按Key分组,每一个Observable发射一组不同的数据
- buffer( ) — 它定期从Observable收集数据到一个集合,然后把这些数据集合打包发射,而不是一次发射一个
- window( ) — 定期将来自Observable的数据分拆成一些Observable窗口,然后发射这些窗口,而不是每次发射一项
- cast( ) — 在发射之前强制将Observable发射的所有数据转换为指定类型
Buffer
定期收集Observable的数据放进一个数据包裹,然后发射这些数据包裹,而不是一次发射一个值。
Buffer
操作符将一个Observable变换为另一个,原来的Observable正常发射数据,变换产生的Observable发射这些数据的缓存集合。Buffer
操作符在很多语言特定的实现中有很多种变体,它们在如何缓存这个问题上存在区别。
注意:如果原来的Observable发射了一个onError
通知,Buffer
会立即传递这个通知,而不是首先发射缓存的数据,即使在这之前缓存中包含了原始Observable发射的数据。
Window
操作符与Buffer
类似,但是它在发射之前把收集到的数据放进单独的Observable,而不是放进一个数据结构。
在RxJava中有许多Buffer
的变体:
buffer(count)
buffer(count)
以列表(List)的形式发射非重叠的缓存,每一个缓存至多包含来自原始Observable的count项数据(最后发射的列表数据可能少于count项)
- Javadoc: buffer(int)
buffer(count, skip)
buffer(count, skip)
从原始Observable的第一项数据开始创建新的缓存,此后每当收到skip
项数据,用count
项数据填充缓存:开头的一项和后续的count-1
项,它以列表(List)的形式发射缓存,取决于count
和skip
的值,这些缓存可能会有重叠部分(比如skip < count时),也可能会有间隙(比如skip > count时)。
- Javadoc: buffer(int,int)
buffer(bufferClosingSelector)
当它订阅原来的Observable时,buffer(bufferClosingSelector)
开始将数据收集到一个List
,然后它调用bufferClosingSelector
生成第二个Observable,当第二个Observable发射一个TClosing
时,buffer
发射当前的List
,然后重复这个过程:开始组装一个新的List
,然后调用bufferClosingSelector
创建一个新的Observable并监视它。它会一直这样做直到原来的Observable执行完成。
- Javadoc: buffer(Func0)
buffer(boundary)
buffer(boundary)
监视一个名叫boundary
的Observable,每当这个Observable发射了一个值,它就创建一个新的List
开始收集来自原始Observable的数据并发射原来的List
。
- Javadoc: buffer(Observable)
- Javadoc: buffer(Observable,int)
buffer(bufferOpenings, bufferClosingSelector)
buffer(bufferOpenings, bufferClosingSelector)
监视这个叫bufferOpenings
的Observable(它发射BufferOpening
对象),每当bufferOpenings
发射了一个数据时,它就创建一个新的List
开始收集原始Observable的数据,并将bufferOpenings
传递给closingSelector
函数。这个函数返回一个Observable。buffer
监视这个Observable,当它检测到一个来自这个Observable的数据时,就关闭List
并且发射它自己的数据(之前的那个List)。
- Javadoc: buffer(Observable,Func1)
buffer(timespan, unit[, scheduler])
buffer(timespan, unit)
定期以List
的形式发射新的数据,每个时间段,收集来自原始Observable的数据(从前面一个数据包裹之后,或者如果是第一个数据包裹,从有观察者订阅原来的Observale之后开始)。还有另一个版本的buffer
接受一个Scheduler
参数,默认情况下会使用computation
调度器。
- Javadoc: buffer(long,TimeUnit)
- Javadoc: buffer(long,TimeUnit,Scheduler)
buffer(timespan, unit, count[, scheduler])
每当收到来自原始Observable的count项数据,或者每过了一段指定的时间后,buffer(timespan, unit, count)
就以List
的形式发射这期间的数据,即使数据项少于count项。还有另一个版本的buffer
接受一个Scheduler
参数,默认情况下会使用computation
调度器。
- Javadoc: buffer(long,TimeUnit,int)
- Javadoc: buffer(long,TimeUnit,int,Scheduler)
buffer(timespan, timeshift, unit[, scheduler])
buffer(timespan, timeshift, unit)
在每一个timeshift
时期内都创建一个新的List
,然后用原始Observable发射的每一项数据填充这个列表(在把这个List
当做自己的数据发射前,从创建时开始,直到过了timespan
这么长的时间)。如果timespan
长于timeshift
,它发射的数据包将会重叠,因此可能包含重复的数据项。
还有另一个版本的buffer
接受一个Scheduler
参数,默认情况下会使用computation
调度器。
- Javadoc: buffer(long,long,TimeUnit)
- Javadoc: buffer(long,long,TimeUnit,Scheduler)
buffer-backpressure
你可以使用Buffer
操作符实现反压backpressure
(意思是,处理这样一个Observable:它产生数据的速度可能比它的观察者消费数据的速度快)。
Buffer操作符可以将大量的数据序列缩减为较少的数据缓存序列,让它们更容易处理。例如,你可以按固定的时间间隔,定期关闭和发射来自一个爆发性Observable的数据缓存。这相当于一个缓冲区。
示例代码
Observable> burstyBuffered = bursty.buffer(500, TimeUnit.MILLISECONDS);
或者,如果你想更进一步,可以在爆发期将数据收集到缓存,然后在爆发期终止时发射这些数据,使用 Debounce
操作符给buffer
操作符发射一个缓存关闭指示器(buffer closing indicator
)可以做到这一点。
代码示例:
// we have to multicast the original bursty Observable so we can use it
// both as our source and as the source for our buffer closing selector:
Observable burstyMulticast = bursty.publish().refCount();
// burstyDebounced will be our buffer closing selector:
Observable burstyDebounced = burstyMulticast.debounce(10, TimeUnit.MILLISECONDS);
// and this, finally, is the Observable of buffers we're interested in:
Observable> burstyBuffered = burstyMulticast.buffer(burstyDebounced);
参见
FlatMap
FlatMap
将一个发射数据的Observable变换为多个Observables,然后将它们发射的数据合并后放进一个单独的Observable
FlatMap
操作符使用一个指定的函数对原始Observable发射的每一项数据执行变换操作,这个函数返回一个本身也发射数据的Observable,然后FlatMap
合并这些Observables发射的数据,最后将合并后的结果当做它自己的数据序列发射。
这个方法是很有用的,例如,当你有一个这样的Observable:它发射一个数据序列,这些数据本身包含Observable成员或者可以变换为Observable,因此你可以创建一个新的Observable发射这些次级Observable发射的数据的完整集合。
注意:FlatMap
对这些Observables发射的数据做的是合并(merge
)操作,因此它们可能是交错的。
在许多语言特定的实现中,还有一个操作符不会让变换后的Observables发射的数据交错,它按照严格的顺序发射这些数据,这个操作符通常被叫作ConcatMap
或者类似的名字。
RxJava将这个操作符实现为flatMap
函数。
注意:如果任何一个通过这个flatMap
操作产生的单独的Observable调用onError
异常终止了,这个Observable自身会立即调用onError
并终止。
这个操作符有一个接受额外的int
参数的一个变体。这个参数设置flatMap
从原来的Observable映射Observables的最大同时订阅数。当达到这个限制时,它会等待其中一个终止然后再订阅另一个。
- Javadoc: flatMap(Func1)
- Javadoc: flatMap(Func1,int)
还有一个版本的flatMap
为原始Observable的每一项数据和每一个通知创建一个新的Observable(并对数据平坦化)。
它也有一个接受额外int
参数的变体。
- Javadoc: flatMap(Func1,Func1,Func0)
- Javadoc: flatMap(Func1,Func1,Func0,int)
还有一个版本的flatMap
会使用原始Observable的数据触发的Observable组合这些数据,然后发射这些数据组合。它也有一个接受额外int
参数的版本。
- Javadoc: flatMap(Func1,Func2)
- Javadoc: flatMap(Func1,Func2,int)
flatMapIterable
flatMapIterable
这个变体成对的打包数据,然后生成Iterable而不是原始数据和生成的Observables,但是处理方式是相同的。
- Javadoc: flatMapIterable(Func1)
- Javadoc: flatMapIterable(Func1,Func2)
concatMap
还有一个concatMap
操作符,它类似于最简单版本的flatMap
,但是它按次序连接而不是合并那些生成的Observables,然后产生自己的数据序列。
- Javadoc: concatMap(Func1)
switchMap
RxJava还实现了switchMap
操作符。它和flatMap
很像,除了一点:当原始Observable发射一个新的数据(Observable)时,它将取消订阅并停止监视产生执之前那个数据的Observable,只监视当前这一个。
- Javadoc: switchMap(Func1)
split
在特殊的StringObservable
类(默认没有包含在RxJava中)中还有一个split
操作符。它将一个发射字符串的Observable转换为另一个发射字符串的Observable,只不过,后者将原始的数据序列当做一个数据流,使用一个正则表达式边界分割它们,然后合并发射分割的结果。
GroupBy
将一个Observable分拆为一些Observables集合,它们中的每一个发射原始Observable的一个子序列
GroupBy
操作符将原始Observable分拆为一些Observables集合,它们中的每一个发射原始Observable数据序列的一个子序列。哪个数据项由哪一个Observable发射是由一个函数判定的,这个函数给每一项指定一个Key,Key相同的数据会被同一个Observable发射。
RxJava实现了groupBy
操作符。它返回Observable的一个特殊子类GroupedObservable
,实现了GroupedObservable
接口的对象有一个额外的方法getKey
,这个Key用于将数据分组到指定的Observable。
有一个版本的groupBy
允许你传递一个变换函数,这样它可以在发射结果GroupedObservable
之前改变数据项。
注意:groupBy
将原始Observable分解为一个发射多个GroupedObservable
的Observable,一旦有订阅,每个GroupedObservable
就开始缓存数据。因此,如果你忽略这些GroupedObservable
中的任何一个,这个缓存可能形成一个潜在的内存泄露。因此,如果你不想观察,也不要忽略GroupedObservable
。你应该使用像take(0)
这样会丢弃自己的缓存的操作符。
如果你取消订阅一个GroupedObservable
,那个Observable将会终止。如果之后原始的Observable又发射了一个与这个Observable的Key匹配的数据,groupBy
将会为这个Key创建一个新的GroupedObservable
。
groupBy
默认不在任何特定的调度器上执行。
- Javadoc: groupBy(Func1)
- Javadoc: groupBy(Func1,Func1)
Map
对Observable发射的每一项数据应用一个函数,执行变换操作
Map
操作符对原始Observable发射的每一项数据应用一个你选择的函数,然后返回一个发射这些结果的Observable。
RxJava将这个操作符实现为map
函数。这个操作符默认不在任何特定的调度器上执行。
- Javadoc: map(Func1)
cast
cast
操作符将原始Observable发射的每一项数据都强制转换为一个指定的类型,然后再发射数据,它是map
的一个特殊版本。
- Javadoc: cast(Class)
下面是常用的操作符列表:
- 创建操作 Create, Defer, Empty/Never/Throw, From, Interval, Just, Range, Repeat, Start, Timer
- 变换操作 Buffer, FlatMap, GroupBy, Map, Scan和Window
- 过滤操作 Debounce, Distinct, ElementAt, Filter, First, IgnoreElements, Last, Sample, Skip, SkipLast, Take, TakeLast
- 组合操作 And/Then/When, CombineLatest, Join, Merge, StartWith, Switch, Zip
- 错误处理 Catch和Retry
- 辅助操作 Delay, Do, Materialize/Dematerialize, ObserveOn, Serialize, Subscribe, SubscribeOn, TimeInterval, Timeout, Timestamp, Using
- 条件和布尔操作 All, Amb, Contains, DefaultIfEmpty, SequenceEqual, SkipUntil, SkipWhile, TakeUntil, TakeWhile
- 算术和集合操作 Average, Concat, Count, Max, Min, Reduce, Sum
- 转换操作 To
- 连接操作 Connect, Publish, RefCount, Replay
- 反压操作,用于增加特殊的流程控制策略的操作符
这些操作符并不全都是ReactiveX的核心组成部分,有一些是语言特定的实现或可选的模块。
RxJava
在RxJava中,一个实现了Observer接口的对象可以订阅(subscribe)一个Observable 类的实例。订阅者(subscriber)对Observable发射(emit)的任何数据或数据序列作出响应。这种模式简化了并发操作,因为它不需要阻塞等待Observable发射数据,而是创建了一个处于待命状态的观察者哨兵,哨兵在未来某个时刻响应Observable的通知。
Single
介绍
RxJava(以及它派生出来的RxGroovy和RxScala)中有一个名为Single的Observable变种。
Single类似于Observable,不同的是,它总是只发射一个值,或者一个错误通知,而不是发射一系列的值。
因此,不同于Observable需要三个方法onNext, onError, onCompleted,订阅Single只需要两个方法:
- onSuccess - Single发射单个的值到这个方法
- onError - 如果无法发射需要的值,Single发射一个Throwable对象到这个方法
Single只会调用这两个方法中的一个,而且只会调用一次,调用了任何一个方法之后,订阅关系终止。
Single的操作符
Single也可以组合使用多种操作,一些操作符让你可以混合使用Observable和Single:
操作符 | 返回值 | 说明 |
---|---|---|
compose | Single | 创建一个自定义的操作符 |
concat and concatWith | Observable | 连接多个Single和Observable发射的数据 |
create | Single | 调用观察者的create方法创建一个Single |
error | Single | 返回一个立即给订阅者发射错误通知的Single |
flatMap | Single | 返回一个Single,它发射对原Single的数据执行flatMap操作后的结果 |
flatMapObservable | Observable | 返回一个Observable,它发射对原Single的数据执行flatMap操作后的结果 |
from | Single | 将Future转换成Single |
just | Single | 返回一个发射一个指定值的Single |
map | Single | 返回一个Single,它发射对原Single的数据执行map操作后的结果 |
merge | Single | 将一个Single(它发射的数据是另一个Single,假设为B)转换成另一个Single(它发射来自另一个Single(B)的数据) |
merge and mergeWith | Observable | 合并发射来自多个Single的数据 |
observeOn | Single | 指示Single在指定的调度程序上调用订阅者的方法 |
onErrorReturn | Single | 将一个发射错误通知的Single转换成一个发射指定数据项的Single |
subscribeOn | Single | 指示Single在指定的调度程序上执行操作 |
timeout | Single | 它给原有的Single添加超时控制,如果超时了就发射一个错误通知 |
toSingle | Single | 将一个发射单个值的Observable转换为一个Single |
zip and zipWith | Single | 将多个Single转换为一个,后者发射的数据是对前者应用一个函数后的结果 |
操作符图示
详细的图解可以参考英文文档:Single
Subject
Subject可以看成是一个桥梁或者代理,在某些ReactiveX实现中(如RxJava),它同时充当了Observer和Observable的角色。因为它是一个Observer,它可以订阅一个或多个Observable;又因为它是一个Observable,它可以转发它收到(Observe)的数据,也可以发射新的数据。
由于一个Subject订阅一个Observable,它可以触发这个Observable开始发射数据(如果那个Observable是"冷"的--就是说,它等待有订阅才开始发射数据)。因此有这样的效果,Subject可以把原来那个"冷"的Observable变成"热"的。
Subject的种类
针对不同的场景一共有四种类型的Subject。他们并不是在所有的实现中全部都存在,而且一些实现使用其它的命名约定(例如,在RxScala中Subject被称作PublishSubject)。
AsyncSubject
一个AsyncSubject只在原始Observable完成后,发射来自原始Observable的最后一个值。(如果原始Observable没有发射任何值,AsyncObject也不发射任何值)它会把这最后一个值发射给任何后续的观察者。BehaviorSubject
当观察者订阅BehaviorSubject时,它开始发射原始Observable最近发射的数据(如果此时还没有收到任何数据,它会发射一个默认值),然后继续发射其它任何来自原始Observable的数据。PublishSubject
PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者。需要注意的是,PublishSubject可能会一创建完成就立刻开始发射数据(除非你可以阻止它发生),因此这里有一个风险:在Subject被创建后到有观察者订阅它之前这个时间段内,一个或多个数据可能会丢失。如果要确保来自原始Observable的所有数据都被分发,你需要这样做:或者使用Create创建那个Observable以便手动给它引入"冷"Observable的行为(当所有观察者都已经订阅时才开始发射数据),或者改用ReplaySubject。ReplaySubject
ReplaySubject会发射所有来自原始Observable的数据给观察者,无论它们是何时订阅的。也有其它版本的ReplaySubject,在重放缓存增长到一定大小的时候或过了一段时间后会丢弃旧的数据(原始Observable发射的)。
如果你把ReplaySubject当作一个观察者使用,注意不要从多个线程中调用它的onNext方法(包括其它的on系列方法),这可能导致同时(非顺序)调用,这会违反Observable协议,给Subject的结果增加了不确定性。
RxJava的对应类
假设你有一个Subject,你想把它传递给其它的代理或者暴露它的Subscriber接口,你可以调用它的asObservable方法,这个方法返回一个Observable。具体使用方法可以参考Javadoc文档。
串行化
如果你把 Subject
当作一个 Subscriber
使用,注意不要从多个线程中调用它的onNext方法(包括其它的on系列方法),这可能导致同时(非顺序)调用,这会违反Observable协议,给Subject的结果增加了不确定性。
要避免此类问题,你可以将 Subject
转换为一个 SerializedSubject
,类似于这样:
mySafeSubject = new SerializedSubject( myUnsafeSubject );
调度器 Scheduler
如果你想给Observable操作符链添加多线程功能,你可以指定操作符(或者特定的Observable)在特定的调度器(Scheduler)上执行。
某些ReactiveX的Observable操作符有一些变体,它们可以接受一个Scheduler参数。这个参数指定操作符将它们的部分或全部任务放在一个特定的调度器上执行。
使用ObserveOn和SubscribeOn操作符,你可以让Observable在一个特定的调度器上执行,ObserveOn指示一个Observable在一个特定的调度器上调用观察者的onNext, onError和onCompleted方法,SubscribeOn更进一步,它指示Observable将全部的处理过程(包括发射数据和通知)放在特定的调度器上执行。
RxJava示例
调度器的种类
下表展示了RxJava中可用的调度器种类:
调度器类型 | 效果 |
---|---|
Schedulers.computation( ) | 用于计算任务,如事件循环或和回调处理,不要用于IO操作(IO操作请使用Schedulers.io());默认线程数等于处理器的数量 |
Schedulers.from(executor) | 使用指定的Executor作为调度器 |
Schedulers.immediate( ) | 在当前线程立即开始执行任务 |
Schedulers.io( ) | 用于IO密集型任务,如异步阻塞IO操作,这个调度器的线程池会根据需要增长;对于普通的计算任务,请使用Schedulers.computation();Schedulers.io( )默认是一个CachedThreadScheduler,很像一个有线程缓存的新线程调度器 |
Schedulers.newThread( ) | 为每个任务创建一个新线程 |
Schedulers.trampoline( ) | 当其它排队的任务完成后,在当前线程排队开始执行 |
默认调度器
在RxJava中,某些Observable操作符的变体允许你设置用于操作执行的调度器,其它的则不在任何特定的调度器上执行,或者在一个指定的默认调度器上执行。下面的表格个列出了一些操作符的默认调度器:
操作符 | 调度器 |
---|---|
buffer(timespan) | computation |
buffer(timespan, count) | computation |
buffer(timespan, timeshift) | computation |
debounce(timeout, unit) | computation |
delay(delay, unit) | computation |
delaySubscription(delay, unit) | computation |
interval | computation |
repeat | trampoline |
replay(time, unit) | computation |
replay(buffersize, time, unit) | computation |
replay(selector, time, unit) | computation |
replay(selector, buffersize, time, unit) | computation |
retry | trampoline |
sample(period, unit) | computation |
skip(time, unit) | computation |
skipLast(time, unit) | computation |
take(time, unit) | computation |
takeLast(time, unit) | computation |
takeLast(count, time, unit) | computation |
takeLastBuffer(time, unit) | computation |
takeLastBuffer(count, time, unit) | computation |
throttleFirst | computation |
throttleLast | computation |
throttleWithTimeout | computation |
timeInterval | immediate |
timeout(timeoutSelector) | immediate |
timeout(firstTimeoutSelector, timeoutSelector) | immediate |
timeout(timeoutSelector, other) | immediate |
timeout(timeout, timeUnit) | computation |
timeout(firstTimeoutSelector, timeoutSelector, other) | immediate |
timeout(timeout, timeUnit, other) | computation |
timer | computation |
timestamp | immediate |
window(timespan) | computation |
window(timespan, count) | computation |
window(timespan, timeshift) | computation |
使用调度器
除了将这些调度器传递给RxJava的Observable操作符,你也可以用它们调度你自己的任务。下面的示例展示了Scheduler.Worker的用法:
worker = Schedulers.newThread().createWorker();
worker.schedule(new Action0() {
@Override
public void call() {
yourWork();
}
});
// some time later...
worker.unsubscribe();
递归调度器
要调度递归的方法调用,你可以使用schedule,然后再用schedule(this),示例:
worker = Schedulers.newThread().createWorker();
worker.schedule(new Action0() {
@Override
public void call() {
yourWork();
// recurse until unsubscribed (schedule will do nothing if unsubscribed)
worker.schedule(this);
}
});
// some time later...
worker.unsubscribe();
检查或设置取消订阅状态
Worker类的对象实现了Subscription接口,使用它的isUnsubscribed和unsubscribe方法,所以你可以在订阅取消时停止任务,或者从正在调度的任务内部取消订阅,示例:
Worker worker = Schedulers.newThread().createWorker();
Subscription mySubscription = worker.schedule(new Action0() {
@Override
public void call() {
while(!worker.isUnsubscribed()) {
status = yourWork();
if(QUIT == status) { worker.unsubscribe(); }
}
}
});
Worker同时是Subscription,因此你可以(通常也应该)调用它的unsubscribe方法通知可以挂起任务和释放资源了。
延时和周期调度器
你可以使用schedule(action,delayTime,timeUnit)在指定的调度器上延时执行你的任务,下面例子中的任务将在500毫秒之后开始执行:
someScheduler.schedule(someAction, 500, TimeUnit.MILLISECONDS);
使用另一个版本的schedule,schedulePeriodically(action,initialDelay,period,timeUnit)方法让你可以安排一个定期执行的任务,下面例子的任务将在500毫秒之后执行,然后每250毫秒执行一次:
someScheduler.schedulePeriodically(someAction, 500, 250, TimeUnit.MILLISECONDS);
测试调度器
TestScheduler让你可以对调度器的时钟表现进行手动微调。这对依赖精确时间安排的任务的测试很有用处。这个调度器有三个额外的方法:
- advanceTimeTo(time,unit) 向前波动调度器的时钟到一个指定的时间点
- advanceTimeBy(time,unit) 将调度器的时钟向前拨动一个指定的时间段
- triggerActions( ) 开始执行任何计划中的但是未启动的任务,如果它们的计划时间等于或者早于调度器时钟的当前时间
操作符分类
ReactiveX的每种编程语言的实现都实现了一组操作符的集合。不同的实现之间有很多重叠的部分,也有一些操作符只存在特定的实现中。每种实现都倾向于用那种编程语言中他们熟悉的上下文中相似的方法给这些操作符命名。
本文首先会给出ReactiveX的核心操作符列表和对应的文档链接,后面还有一个决策树用于帮助你根据具体的场景选择合适的操作符。最后有一个语言特定实现的按字母排序的操作符列表。
如果你想实现你自己的操作符,可以参考这里:实现自定义操作符
创建操作
用于创建Observable的操作符
-
Create
— 通过调用观察者的方法从头创建一个Observable -
Defer
— 在观察者订阅之前不创建这个Observable,为每一个观察者创建一个新的Observable -
Empty/Never/Throw
— 创建行为受限的特殊Observable -
From
— 将其它的对象或数据结构转换为Observable -
Interval
— 创建一个定时发射整数序列的Observable -
Just
— 将对象或者对象集合转换为一个会发射这些对象的Observable -
Range
— 创建发射指定范围的整数序列的Observable -
Repeat
— 创建重复发射特定的数据或数据序列的Observable -
Start
— 创建发射一个函数的返回值的Observable -
Timer
— 创建在一个指定的延迟之后发射单个数据的Observable
变换操作
这些操作符可用于对Observable发射的数据进行变换,详细解释可以看每个操作符的文档
-
Buffer
— 缓存,可以简单的理解为缓存,它定期从Observable收集数据到一个集合,然后把这些数据集合打包发射,而不是一次发射一个 -
FlatMap
— 扁平映射,将Observable发射的数据变换为Observables集合,然后将这些Observable发射的数据平坦化的放进一个单独的Observable,可以认为是一个将嵌套的数据结构展开的过程。 -
GroupBy
— 分组,将原来的Observable分拆为Observable集合,将原始Observable发射的数据按Key分组,每一个Observable发射一组不同的数据 -
Map
— 映射,通过对序列的每一项都应用一个函数变换Observable发射的数据,实质是对序列中的每一项执行一个函数,函数的参数就是这个数据项 -
Scan
— 扫描,对Observable发射的每一项数据应用一个函数,然后按顺序依次发射这些值 -
Window
— 窗口,定期将来自Observable的数据分拆成一些Observable窗口,然后发射这些窗口,而不是每次发射一项。类似于Buffer,但Buffer发射的是数据,Window发射的是Observable,每一个Observable发射原始Observable的数据的一个子集
过滤操作
这些操作符用于从Observable发射的数据中进行选择
-
Debounce
— 只有在空闲了一段时间后才发射数据,通俗的说,就是如果一段时间没有操作,就执行一次操作 -
Distinct
— 去重,过滤掉重复数据项 -
ElementAt
— 取值,取特定位置的数据项 -
Filter
— 过滤,过滤掉没有通过谓词测试的数据项,只发射通过测试的 -
First
— 首项,只发射满足条件的第一条数据 -
IgnoreElements
— 忽略所有的数据,只保留终止通知(onError或onCompleted) -
Last
— 末项,只发射最后一条数据 -
Sample
— 取样,定期发射最新的数据,等于是数据抽样,有的实现里叫ThrottleFirst -
Skip
— 跳过前面的若干项数据 -
SkipLast
— 跳过后面的若干项数据 -
Take
— 只保留前面的若干项数据 -
TakeLast
— 只保留后面的若干项数据
组合操作
组合操作符用于将多个Observable组合成一个单一的Observable
-
And/Then/When
— 通过模式(And条件)和计划(Then次序)组合两个或多个Observable发射的数据集 -
CombineLatest
— 当两个Observables中的任何一个发射了一个数据时,通过一个指定的函数组合每个Observable发射的最新数据(一共两个数据),然后发射这个函数的结果 -
Join
— 无论何时,如果一个Observable发射了一个数据项,只要在另一个Observable发射的数据项定义的时间窗口内,就将两个Observable发射的数据合并发射 -
Merge
— 将两个Observable发射的数据组合并成一个 -
StartWith
— 在发射原来的Observable的数据序列之前,先发射一个指定的数据序列或数据项 -
Switch
— 将一个发射Observable序列的Observable转换为这样一个Observable:它逐个发射那些Observable最近发射的数据 -
Zip
— 打包,使用一个指定的函数将多个Observable发射的数据组合在一起,然后将这个函数的结果作为单项数据发射
错误处理
这些操作符用于从错误通知中恢复
-
Catch
— 捕获,继续序列操作,将错误替换为正常的数据,从onError通知中恢复 -
Retry
— 重试,如果Observable发射了一个错误通知,重新订阅它,期待它正常终止
辅助操作
一组用于处理Observable的操作符
-
Delay
— 延迟一段时间发射结果数据 -
Do
— 注册一个动作占用一些Observable的生命周期事件,相当于Mock某个操作 -
Materialize/Dematerialize
— 将发射的数据和通知都当做数据发射,或者反过来 -
ObserveOn
— 指定观察者观察Observable的调度程序(工作线程) -
Serialize
— 强制Observable按次序发射数据并且功能是有效的 -
Subscribe
— 收到Observable发射的数据和通知后执行的操作 -
SubscribeOn
— 指定Observable应该在哪个调度程序上执行 -
TimeInterval
— 将一个Observable转换为发射两个数据之间所耗费时间的Observable -
Timeout
— 添加超时机制,如果过了指定的一段时间没有发射数据,就发射一个错误通知 -
Timestamp
— 给Observable发射的每个数据项添加一个时间戳 -
Using
— 创建一个只在Observable的生命周期内存在的一次性资源
条件和布尔操作
这些操作符可用于单个或多个数据项,也可用于Observable
-
All
— 判断Observable发射的所有的数据项是否都满足某个条件 -
Amb
— 给定多个Observable,只让第一个发射数据的Observable发射全部数据 -
Contains
— 判断Observable是否会发射一个指定的数据项 -
DefaultIfEmpty
— 发射来自原始Observable的数据,如果原始Observable没有发射数据,就发射一个默认数据 -
SequenceEqual
— 判断两个Observable是否按相同的数据序列 -
SkipUntil
— 丢弃原始Observable发射的数据,直到第二个Observable发射了一个数据,然后发射原始Observable的剩余数据 -
SkipWhile
— 丢弃原始Observable发射的数据,直到一个特定的条件为假,然后发射原始Observable剩余的数据 -
TakeUntil
— 发射来自原始Observable的数据,直到第二个Observable发射了一个数据或一个通知 -
TakeWhile
— 发射原始Observable的数据,直到一个特定的条件为真,然后跳过剩余的数据
算术和聚合操作
这些操作符可用于整个数据序列
-
Average
— 计算Observable发射的数据序列的平均值,然后发射这个结果 -
Concat
— 不交错的连接多个Observable的数据 -
Count
— 计算Observable发射的数据个数,然后发射这个结果 -
Max
— 计算并发射数据序列的最大值 -
Min
— 计算并发射数据序列的最小值 -
Reduce
— 按顺序对数据序列的每一个应用某个函数,然后返回这个值 -
Sum
— 计算并发射数据序列的和
连接操作
一些有精确可控的订阅行为的特殊Observable
-
Connect
— 指示一个可连接的Observable开始发射数据给订阅者 -
Publish
— 将一个普通的Observable转换为可连接的 -
RefCount
— 使一个可连接的Observable表现得像一个普通的Observable -
Replay
— 确保所有的观察者收到同样的数据序列,即使他们在Observable开始发射数据之后才订阅
转换操作
-
To
— 将Observable转换为其它的对象或数据结构 -
Blocking
阻塞Observable的操作符
操作符决策树
几种主要的需求
- 直接创建一个Observable(创建操作)
- 组合多个Observable(组合操作)
- 对Observable发射的数据执行变换操作(变换操作)
- 从Observable发射的数据中取特定的值(过滤操作)
- 转发Observable的部分值(条件/布尔/过滤操作)
- 对Observable发射的数据序列求值(算术/聚合操作)
这个页面展示了创建Observable的各种方法。
- just( ) — 将一个或多个对象转换成发射这个或这些对象的一个Observable
- from( ) — 将一个Iterable, 一个Future, 或者一个数组转换成一个Observable
- repeat( ) — 创建一个重复发射指定数据或数据序列的Observable
- repeatWhen( ) — 创建一个重复发射指定数据或数据序列的Observable,它依赖于另一个Observable发射的数据
- create( ) — 使用一个函数从头创建一个Observable
- defer( ) — 只有当订阅者订阅才创建Observable;为每个订阅创建一个新的Observable
- range( ) — 创建一个发射指定范围的整数序列的Observable
- interval( ) — 创建一个按照给定的时间间隔发射整数序列的Observable
- timer( ) — 创建一个在给定的延时之后发射单个数据的Observable
- empty( ) — 创建一个什么都不做直接通知完成的Observable
- error( ) — 创建一个什么都不做直接通知错误的Observable
- never( ) — 创建一个不发射任何数据的Observable