Distinct
抑制(过滤掉)重复的数据项
Distinct
的过滤规则是:只允许还没有发射过的数据项通过。
在某些实现中,有一些变体允许你调整判定两个数据不同(distinct
)的标准。还有一些实现只比较一项数据和它的直接前驱,因此只会从序列中过滤掉连续重复的数据。
distinct()
RxJava将这个操作符实现为distinct
函数。
示例代码
Observable.just(1, 2, 1, 1, 2, 3)
.distinct()
.subscribe(new Subscriber() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
输出
Next: 1
Next: 2
Next: 3
Sequence complete.
- Javadoc: distinct()
distinct(Func1)
这个操作符有一个变体接受一个函数。这个函数根据原始Observable发射的数据项产生一个Key,然后,比较这些Key而不是数据本身,来判定两个数据是否是不同的。
- Javadoc: distinct(Func1)
distinctUntilChanged
RxJava还是实现了一个distinctUntilChanged
操作符。它只判定一个数据和它的直接前驱是否是不同的。
distinctUntilChanged(Func1)
和distinct(Func1)
一样,根据一个函数产生的Key判定两个相邻的数据项是不是不同的。
- Javadoc: distinctUntilChanged(Func1)
distinct
和distinctUntilChanged
默认不在任何特定的调度器上执行。
ElementAt
只发射第N项数据
ElementAt
操作符获取原始Observable发射的数据序列指定索引位置的数据项,然后当做自己的唯一数据发射。
RxJava将这个操作符实现为elementAt
,给它传递一个基于0的索引值,它会发射原始Observable数据序列对应索引位置的值,如果你传递给elementAt
的值为5,那么它会发射第六项的数据。
如果你传递的是一个负数,或者原始Observable的数据项数小于index+1
,将会抛出一个IndexOutOfBoundsException
异常。
- Javadoc: elementAt(int)
elementAtOrDefault
RxJava还实现了elementAtOrDefault
操作符。与elementAt
的区别是,如果索引值大于数据项数,它会发射一个默认值(通过额外的参数指定),而不是抛出异常。但是如果你传递一个负数索引值,它仍然会抛出一个IndexOutOfBoundsException
异常。
- Javadoc: elementAtOrDefault(int,T)
elementAt
和elementAtOrDefault
默认不在任何特定的调度器上执行。
Filter
只发射通过了谓词测试的数据项
Filter
操作符使用你指定的一个谓词函数测试数据项,只有通过测试的数据才会被发射。
RxJava将这个操作符实现为filter
函数。
示例代码
Observable.just(1, 2, 3, 4, 5)
.filter(new Func1() {
@Override
public Boolean call(Integer item) {
return( item < 4 );
}
}).subscribe(new Subscriber() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
输出
Next: 1
Next: 2
Next: 3
Sequence complete.
filter
默认不在任何特定的调度器上执行。
- Javadoc: filter(Func1)
ofType
ofType
是filter
操作符的一个特殊形式。它过滤一个Observable只返回指定类型的数据。
ofType
默认不在任何特定的调度器上指定。
- Javadoc: ofType(Class)
First
只发射第一项(或者满足某个条件的第一项)数据
如果你只对Observable发射的第一项数据,或者满足某个条件的第一项数据感兴趣,你可以使用First
操作符。
在某些实现中,First
没有实现为一个返回Observable的过滤操作符,而是实现为一个在当时就发射原始Observable指定数据项的阻塞函数。在这些实现中,如果你想要的是一个过滤操作符,最好使用Take(1)
或者ElementAt(0)
。
在一些实现中还有一个Single
操作符。它的行为与First
类似,但为了确保只发射单个值,它会等待原始Observable终止(否则,不是发射那个值,而是以一个错误通知终止)。你可以使用它从原始Observable获取第一项数据,而且也确保只发射一项数据。
在RxJava中,这个操作符被实现为first
,firstOrDefault
和takeFirst
。
可能容易混淆,BlockingObservable
也有名叫first
和firstOrDefault
的操作符,它们会阻塞并返回值,不是立即返回一个Observable。
还有几个其它的操作符执行类似的功能。
IgnoreElements
不发射任何数据,只发射Observable的终止通知
IgnoreElements
操作符抑制原始Observable发射的所有数据,只允许它的终止通知(onError
或onCompleted
)通过。
如果你不关心一个Observable发射的数据,但是希望在它完成时或遇到错误终止时收到通知,你可以对Observable使用ignoreElements
操作符,它会确保永远不会调用观察者的onNext()
方法。
RxJava将这个操作符实现为ignoreElements
。
- Javadoc: ignoreElements()
ignoreElements
默认不在任何特定的调度器上执行。
Last
只发射最后一项(或者满足某个条件的最后一项)数据
如果你只对Observable发射的最后一项数据,或者满足某个条件的最后一项数据感兴趣,你可以使用Last
操作符。
在某些实现中,Last
没有实现为一个返回Observable的过滤操作符,而是实现为一个在当时就发射原始Observable指定数据项的阻塞函数。在这些实现中,如果你想要的是一个过滤操作符,最好使用TakeLast(1)
。
在RxJava中的实现是last
和lastOrDefault
。
可能容易混淆,BlockingObservable
也有名叫last
和lastOrDefault
的操作符,它们会阻塞并返回值,不是立即返回一个Observable。
过滤操作符
只发射最后一项数据,使用没有参数的last
操作符。
示例代码
Observable.just(1, 2, 3)
.last()
.subscribe(new Subscriber() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
输出
Next: 3
Sequence complete.
- Javadoc: last()
这个版本的last
也是接受一个谓词函数,返回一个发射原始Observable中满足条件的最后一项数据的Observable。
- Javadoc: last(Func1)
lastOrDefault
与last
类似,不同的是,如果原始Observable没有发射任何值,它发射你指定的默认值。
- Javadoc: lastOrDefault(T)
这个版本的lastOrDefault
可以接受一个谓词函数,如果有数据满足条件,返回的Observable就发射原始Observable满足条件的最后一项数据,否则发射默认值。
- Javadoc: lastOrDefault(T)
last
和lastOrDefault
默认不在任何特定的调度器上执行。
Sample
定期发射Observable最近发射的数据项
Sample
操作符定时查看一个Observable,然后发射自上次采样以来它最近发射的数据。
在某些实现中,有一个ThrottleFirst
操作符的功能类似,但不是发射采样期间的最近的数据,而是发射在那段时间内的第一项数据。
RxJava将这个操作符实现为sample
和throttleLast
。
注意:如果自上次采样以来,原始Observable没有发射任何数据,这个操作返回的Observable在那段时间内也不会发射任何数据。
sample
(别名throttleLast
)的一个变体按照你参数中指定的时间间隔定时采样(TimeUnit
指定时间单位)。
sample
的这个变体默认在computation
调度器上执行,但是你可以使用第三个参数指定其它的调度器。
- Javadoc: sample(long,TimeUnit)和throttleLast(long,TimeUnit)
- Javadoc: sample(long,TimeUnit,Scheduler)和throttleLast(long,TimeUnit,Scheduler)
sample
的这个变体每当第二个Observable发射一个数据(或者当它终止)时就对原始Observable进行采样。第二个Observable通过参数传递给sample
。
sample
的这个变体默认不在任何特定的调度器上执行。
- Javadoc: sample(Observable)
throttleFirst
与throttleLast/sample
不同,在每个采样周期内,它总是发射原始Observable的第一项数据,而不是最近的一项。
throttleFirst
操作符默认在computation
调度器上执行,但是你可以使用第三个参数指定其它的调度器。
- Javadoc: throttleFirst(long,TimeUnit)
- Javadoc: throttleFirst(long,TimeUnit,Scheduler)
Skip
抑制Observable发射的前N项数据
使用Skip
操作符,你可以忽略Observable'发射的前N项数据,只保留之后的数据。
RxJava中这个操作符叫skip
。skip
的这个变体默认不在任何特定的调度器上执行。
- Javadoc: skip(int)
skip
的这个变体接受一个时长而不是数量参数。它会丢弃原始Observable开始的那段时间发射的数据,时长和时间单位通过参数指定。
skip
的这个变体默认在computation
调度器上执行,但是你可以使用第三个参数指定其它的调度器。
- Javadoc: skip(long,TimeUnit)
- Javadoc: skip(long,TimeUnit,Scheduler)
SkipLast
抑制Observable发射的后N项数据
使用SkipLast
操作符修改原始Observable,你可以忽略Observable'发射的后N项数据,只保留前面的数据。
[图片上传失败...(image-b2ec0-1572187529963)]
使用SkipLast
操作符,你可以忽略原始Observable发射的后N项数据,只保留之前的数据。注意:这个机制是这样实现的:延迟原始Observable发射的任何数据项,直到它发射了N项数据。
skipLast
的这个变体默认不在任何特定的调度器上执行。
- Javadoc: skipLast(int)
还有一个skipLast
变体接受一个时长而不是数量参数。它会丢弃在原始Observable的生命周期内最后一段时间内发射的数据。时长和时间单位通过参数指定。
注意:这个机制是这样实现的:延迟原始Observable发射的任何数据项,直到自这次发射之后过了给定的时长。
skipLast
的这个变体默认在computation
调度器上执行,但是你可以使用第三个参数指定其它的调度器。
- Javadoc: skipLast(long,TimeUnit)
- Javadoc: skipLast(long,TimeUnit,Scheduler)
Take
只发射前面的N项数据
使用Take
操作符让你可以修改Observable的行为,只返回前面的N项数据,然后发射完成通知,忽略剩余的数据。
RxJava将这个操作符实现为take
函数。
如果你对一个Observable使用take(n)
(或它的同义词limit(n)
)操作符,而那个Observable发射的数据少于N项,那么take
操作生成的Observable不会抛异常或发射onError
通知,在完成前它只会发射相同的少量数据。
示例代码
Observable.just(1, 2, 3, 4, 5, 6, 7, 8)
.take(4)
.subscribe(new Subscriber() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
输出
Next: 1
Next: 2
Next: 3
Next: 4
Sequence complete.
take(int)
默认不任何特定的调度器上执行。
- Javadoc: take(int)
take
的这个变体接受一个时长而不是数量参数。它会丢发射Observable开始的那段时间发射的数据,时长和时间单位通过参数指定。
take
的这个变体默认在computation
调度器上执行,但是你可以使用第三个参数指定其它的调度器。
- Javadoc: take(long,TimeUnit)
- Javadoc: take(long,TimeUnit,Scheduler)
TakeLast
发射Observable发射的最后N项数据
使用TakeLast
操作符修改原始Observable,你可以只发射Observable'发射的后N项数据,忽略前面的数据。
taskLast.n
使用takeLast
操作符,你可以只发射原始Observable发射的后N项数据,忽略之前的数据。注意:这会延迟原始Observable发射的任何数据项,直到它全部完成。
takeLast
的这个变体默认不在任何特定的调度器上执行。
- Javadoc: takeLast(int)
takeLast.t
还有一个takeLast
变体接受一个时长而不是数量参数。它会发射在原始Observable的生命周期内最后一段时间内发射的数据。时长和时间单位通过参数指定。
注意:这会延迟原始Observable发射的任何数据项,直到它全部完成。
takeLast
的这个变体默认在computation
调度器上执行,但是你可以使用第三个参数指定其它的调度器。
takeLastBuffer
还有一个操作符叫takeLastBuffer
,它和takeLast
类似,,唯一的不同是它把所有的数据项收集到一个List
再发射,而不是依次发射一个。
- Javadoc: takeLastBuffer(int)
- Javadoc: takeLastBuffer(long,TimeUnit)
- Javadoc: takeLastBuffer(long,TimeUnit,Scheduler)
- Javadoc: takeLastBuffer(int,long,TimeUnit)
- Javadoc: takeLastBuffer(int,long,TimeUnit,Scheduler)
结合操作
这个页面展示的操作符可用于组合多个Observables。
- startWith( ) — 在数据序列的开头增加一项数据
- merge( ) — 将多个Observable合并为一个
- mergeDelayError( ) — 合并多个Observables,让没有错误的Observable都完成后再发射错误通知
- zip( ) — 使用一个函数组合多个Observable发射的数据集合,然后再发射这个结果
- and( ), then( ), and when( ) — (
rxjava-joins
) 通过模式和计划组合多个Observables发射的数据集合 - combineLatest( ) — 当两个Observables中的任何一个发射了一个数据时,通过一个指定的函数组合每个Observable发射的最新数据(一共两个数据),然后发射这个函数的结果
- join( ) and groupJoin( ) — 无论何时,如果一个Observable发射了一个数据项,只要在另一个Observable发射的数据项定义的时间窗口内,就将两个Observable发射的数据合并发射
- switchOnNext( ) — 将一个发射Observables的Observable转换成另一个Observable,后者发射这些Observables最近发射的数据
(
rxjava-joins
) — 表示这个操作符当前是可选的rxjava-joins
包的一部分,还没有包含在标准的RxJava操作符集合里
And/Then/When
使用Pattern和Plan作为中介,将两个或多个Observable发射的数据集合并到一起
And/Then/When操作符组合的行为类似于zip
,但是它们使用一个中间数据结构。接受两个或多个Observable,一次一个将它们的发射物合并到Pattern
对象,然后操作那个Pattern
对象,变换为一个Plan
。随后将这些Plan
变换为Observable的发射物。
它们属于rxjava-joins
模块,不是核心RxJava包的一部分
CombineLatest
当两个Observables中的任何一个发射了数据时,使用一个函数结合每个Observable发射的最近数据项,并且基于这个函数的结果发射数据。
CombineLatest
操作符行为类似于zip
,但是只有当原始的Observable中的每一个都发射了一条数据时zip
才发射数据。CombineLatest
则在原始的Observable中任意一个发射了数据时发射一条数据。当原始Observables的任何一个发射了一条数据时,CombineLatest
使用一个函数结合它们最近发射的数据,然后发射这个函数的返回值。
RxJava将这个操作符实现为combineLatest
,它接受二到九个Observable作为参数,或者单个Observables列表作为参数。它默认不在任何特定的调度器上执行。
- Javadoc: combineLatest(List,FuncN)
- Javadoc: combineLatest(Observable,Observable,Func2)
withLatestFrom
withLatestFrom
操作符还在开发中,不是1.0版本的一部分。类似于combineLatest
,但是只在单个原始Observable发射了一条数据时才发射数据。
Join
任何时候,只要在另一个Observable发射的数据定义的时间窗口内,这个Observable发射了一条数据,就结合两个Observable发射的数据。
Join
操作符结合两个Observable发射的数据,基于时间窗口(你定义的针对每条数据特定的原则)选择待集合的数据项。你将这些时间窗口实现为一些Observables,它们的生命周期从任何一条Observable发射的每一条数据开始。当这个定义时间窗口的Observable发射了一条数据或者完成时,与这条数据关联的窗口也会关闭。只要这条数据的窗口是打开的,它将继续结合其它Observable发射的任何数据项。你定义一个用于结合数据的函数。
很多ReactiveX实现还有一个类似的GroupJoin
操作符。
Most ReactiveX implementations that have a Join operator also have a GroupJoin operator that is similar, except that the function you define to combine items emitted by the two Observables pairs individual items emitted by the source Observable not with an item from the second Observable, but with an Observable that emits items from the second Observable that fall in the same window.
The join
operator takes four parameters:
- the second Observable to combine with the source Observable
- a function that accepts an item from the source Observable and returns an Observable whose lifespan governs the duration during which that item will combine with items from the second Observable
- a function that accepts an item from the second Observable and returns an Observable whose lifespan governs the duration during which that item will combine with items from the first Observable
- a function that accepts an item from the first Observable and an item from the second Observable and returns an item to be emitted by the Observable returned from join
join
默认不在任何特定的调度器上执行。
- Javadoc: Join(Observable,Func1,Func1,Func2)
[图片上传失败...(image-2198cc-1572187529963)]
The groupJoin
operator takes four parameters:
- the second Observable to combine with the source Observable
- a function that accepts an item from the source Observable and returns an Observable whose lifespan governs the duration during which that item will combine with items from the second Observable
- a function that accepts an item from the second Observable and returns an Observable whose lifespan governs the duration during which that item will combine with items from the first Observable
- a function that accepts an item from the first Observable and an Observable that emits items from the second Observable and returns an item to be emitted by the Observable returned from groupJoin
groupJoin
默认不在任何特定的调度器上执行。
- Javadoc: groupJoin(Observable,Func1,Func1,Func2)
可选的StringObservable
类中也有一个join
操作符。它将一个发射字符串序列的Observable转换为一个发射单个字符串的Observable,join
操作符使用指定的定界符将全部单独的字符串连接起来。
Merge
合并多个Observables的发射物
使用Merge
操作符你可以将多个Observables的输出合并,就好像它们是一个单个的Observable一样。
Merge
可能会让合并的Observables发射的数据交错(有一个类似的操作符Concat
不会让数据交错,它会按顺序一个接着一个发射多个Observables的发射物)。
正如图例上展示的,任何一个原始Observable的onError
通知会被立即传递给观察者,而且会终止合并后的Observable。
在很多ReactiveX实现中还有一个叫MergeDelayError
的操作符,它的行为有一点不同,它会保留onError
通知直到合并后的Observable所有的数据发射完成,在那时它才会把onError
传递给观察者。
RxJava将它实现为merge
, mergeWith
和mergeDelayError
。
示例代码
Observable odds = Observable.just(1, 3, 5).subscribeOn(someScheduler);
Observable evens = Observable.just(2, 4, 6);
Observable.merge(odds, evens)
.subscribe(new Subscriber() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
输出
Next: 1
Next: 3
Next: 5
Next: 2
Next: 4
Next: 6
Sequence complete.
- Javadoc: merge(Iterable)
- Javadoc: merge(Iterable,int)
- Javadoc: [merge(Observable])
- Javadoc: merge(Observable,Observable) (接受二到九个Observable)
除了传递多个Observable给merge
,你还可以传递一个Observable列表List
,数组,甚至是一个发射Observable序列的Observable,merge
将合并它们的输出作为单个Observable的输出:
如果你传递一个发射Observables序列的Observable,你可以指定merge
应该同时订阅的Observable'的最大数量。一旦达到订阅数的限制,它将不再订阅原始Observable发射的任何其它Observable,直到某个已经订阅的Observable发射了onCompleted
通知。
- Javadoc: merge(Observable)
- Javadoc: merge(Observable,int)
merge
是静态方法,mergeWith
是对象方法,举个例子,Observable.merge(odds,evens)
等价于odds.mergeWith(evens)
。
如果传递给merge
的任何一个的Observable发射了onError
通知终止了,merge
操作符生成的Observable也会立即以onError
通知终止。如果你想让它继续发射数据,在最后才报告错误,可以使用mergeDelayError
。
mergeDelayError
behaves much like merge
. The exception is when one of the Observables being merged terminates with an onError notification. If this happens with merge, the merged Observable will immediately issue an onError
notification and terminate. mergeDelayError
, on the other hand, will hold off on reporting the error until it has given any other non-error-producing Observables that it is merging a chance to finish emitting their items, and it will emit those itself, and will only terminate with an onError
notification when all of the other merged Observables have finished.
Because it is possible that more than one of the merged Observables encountered an error, mergeDelayError
may pass information about multiple errors in the onError notification (it will never invoke the observer’s onError
method more than once). For this reason, if you want to know the nature of these errors, you should write your observers’ onError methods so that they accept a parameter of the class CompositeException
.
mergeDelayError
has fewer variants. You cannot pass it an Iterable or Array of Observables, but you can pass it an Observable that emits Observables or between one and nine individual Observables as parameters. There is not an instance method version of mergeDelayError
as there is for merge
.
- Javadoc: mergeDelayError(Observable)
- Javadoc: mergeDelayError(Observable,Observable)
StartWith
在数据序列的开头插入一条指定的项
如果你想要一个Observable在发射数据之前先发射一个指定的数据序列,可以使用StartWith
操作符。(如果你想一个Observable发射的数据末尾追加一个数据序列可以使用Concat
操作符。)
可接受一个Iterable或者多个Observable作为函数的参数。
- Javadoc: startWith(Iterable)
- Javadoc: startWith(T) (最多接受九个参数)
你也可以传递一个Observable给startWith
,它会将那个Observable的发射物插在原始Observable发射的数据序列之前,然后把这个当做自己的发射物集合。这可以看作是Concat
的反转。
- Javadoc: startWith(Observable)
Switch
将一个发射多个Observables的Observable转换成另一个单独的Observable,后者发射那些Observables最近发射的数据项
Switch
订阅一个发射多个Observables的Observable。它每次观察那些Observables中的一个,Switch
返回的这个Observable取消订阅前一个发射数据的Observable,开始发射最近的Observable发射的数据。注意:当原始Observable发射了一个新的Observable时(不是这个新的Observable发射了一条数据时),它将取消订阅之前的那个Observable。这意味着,在后来那个Observable产生之后到它开始发射数据之前的这段时间里,前一个Observable发射的数据将被丢弃(就像图例上的那个黄色圆圈一样)。
Java将这个操作符实现为switchOnNext
。它默认不在任何特定的调度器上执行。
- Javadoc: switchOnNext(Observable)
Zip
通过一个函数将多个Observables的发射物结合到一起,基于这个函数的结果为每个结合体发射单个数据项。
Zip
操作符返回一个Obversable,它使用这个函数按顺序结合两个或多个Observables发射的数据项,然后它发射这个函数返回的结果。它按照严格的顺序应用这个函数。它只发射与发射数据项最少的那个Observable一样多的数据。
RxJava将这个操作符实现为zip
和zipWith
。
zip
的最后一个参数接受每个Observable发射的一项数据,返回被压缩后的数据,它可以接受一到九个参数:一个Observable序列,或者一些发射Observable的Observables。
- Javadoc: zip(Iterable,FuncN)
- Javadoc: zip(Observable,FuncN)
- Javadoc: zip(Observable,Observable,Func2) (最多可以有九个Observables参数)
zipWith
zipWith
操作符总是接受两个参数,第一个参数是一个Observable或者一个Iterable。
- Javadoc: zipWith(Observable,Func2)
- Javadoc: zipWith(Iterable,Func2)
zip
和zipWith
默认不在任何特定的操作符上执行。
错误处理
很多操作符可用于对Observable发射的onError
通知做出响应或者从错误中恢复,例如,你可以:
- 吞掉这个错误,切换到一个备用的Observable继续发射数据
- 吞掉这个错误然后发射默认值
- 吞掉这个错误并立即尝试重启这个Observable
- 吞掉这个错误,在一些回退间隔后重启这个Observable
这是操作符列表:
- onErrorResumeNext( ) — 指示Observable在遇到错误时发射一个数据序列
- onErrorReturn( ) — 指示Observable在遇到错误时发射一个特定的数据
- onExceptionResumeNext( ) — instructs an Observable to continue emitting items after it encounters an exception (but not another variety of throwable)指示Observable遇到错误时继续发射数据
- retry( ) — 指示Observable遇到错误时重试
- retryWhen( ) — 指示Observable遇到错误时,将错误传递给另一个Observable来决定是否要重新给订阅这个Observable
Catch
从onError
通知中恢复发射数据
Catch
操作符拦截原始Observable的onError
通知,将它替换为其它的数据项或数据序列,让产生的Observable能够正常终止或者根本不终止。
在某些ReactiveX的实现中,有一个叫onErrorResumeNext
的操作符,它的行为与Catch
相似。
RxJava将Catch
实现为三个不同的操作符:
onErrorReturn
让Observable遇到错误时发射一个特殊的项并且正常终止。
onErrorResumeNext
让Observable在遇到错误时开始发射第二个Observable的数据序列。
onExceptionResumeNext
让Observable在遇到错误时继续发射后面的数据项。
onErrorReturn
onErrorReturn
方法返回一个镜像原有Observable行为的新Observable,后者会忽略前者的onError
调用,不会将错误传递给观察者,作为替代,它会发发射一个特殊的项并调用观察者的onCompleted
方法。
- Javadoc: onErrorReturn(Func1)
onErrorResumeNext
onErrorResumeNext
方法返回一个镜像原有Observable行为的新Observable,后者会忽略前者的onError
调用,不会将错误传递给观察者,作为替代,它会开始镜像另一个,备用的Observable。
- Javadoc: onErrorResumeNext(Func1)
- Javadoc: onErrorResumeNext(Observable)
onExceptionResumeNext
和onErrorResumeNext
类似,onExceptionResumeNext
方法返回一个镜像原有Observable行为的新Observable,也使用一个备用的Observable,不同的是,如果onError
收到的Throwable
不是一个Exception
,它会将错误传递给观察者的onError
方法,不会使用备用的Observable。
- Javadoc: onExceptionResumeNext(Observable)
Retry
如果原始Observable遇到错误,重新订阅它期望它能正常终止
Retry
操作符不会将原始Observable的onError
通知传递给观察者,它会订阅这个Observable,再给它一次机会无错误地完成它的数据序列。Retry
总是传递onNext
通知给观察者,由于重新订阅,可能会造成数据项重复,如上图所示。
RxJava中的实现为retry
和retryWhen
。
无论收到多少次onError
通知,无参数版本的retry
都会继续订阅并发射原始Observable。
接受单个count
参数的retry
会最多重新订阅指定的次数,如果次数超了,它不会尝试再次订阅,它会把最新的一个onError
通知传递给它的观察者。
还有一个版本的retry
接受一个谓词函数作为参数,这个函数的两个参数是:重试次数和导致发射onError
通知的Throwable
。这个函数返回一个布尔值,如果返回true
,retry
应该再次订阅和镜像原始的Observable,如果返回false
,retry
会将最新的一个onError
通知传递给它的观察者。
retry
操作符默认在trampoline
调度器上执行。
- Javadoc: retry()
- Javadoc: retry(long)
- Javadoc: retry(Func2)
retryWhen
retryWhen
和retry
类似,区别是,retryWhen
将onError
中的Throwable
传递给一个函数,这个函数产生另一个Observable,retryWhen
观察它的结果再决定是不是要重新订阅原始的Observable。如果这个Observable发射了一项数据,它就重新订阅,如果这个Observable发射的是onError
通知,它就将这个通知传递给观察者然后终止。
retryWhen
默认在trampoline
调度器上执行,你可以通过参数指定其它的调度器。
示例代码
Observable.create((Subscriber super String> s) -> {
System.out.println("subscribing");
s.onError(new RuntimeException("always fails"));
}).retryWhen(attempts -> {
return attempts.zipWith(Observable.range(1, 3), (n, i) -> i).flatMap(i -> {
System.out.println("delay retry by " + i + " second(s)");
return Observable.timer(i, TimeUnit.SECONDS);
});
}).toBlocking().forEach(System.out::println);
输出
subscribing
delay retry by 1 second(s)
subscribing
delay retry by 2 second(s)
subscribing
delay retry by 3 second(s)
subscribing
- Javadoc: retryWhen(Func1)
- Javadoc: retryWhen(Func1,Scheduler)
辅助操作
这个页面列出了很多用于Observable的辅助操作符
- materialize( ) — 将Observable转换成一个通知列表convert an Observable into a list of Notifications
- dematerialize( ) — 将上面的结果逆转回一个Observable
- timestamp( ) — 给Observable发射的每个数据项添加一个时间戳
- serialize( ) — 强制Observable按次序发射数据并且要求功能是完好的
- cache( ) — 记住Observable发射的数据序列并发射相同的数据序列给后续的订阅者
- observeOn( ) — 指定观察者观察Observable的调度器
- subscribeOn( ) — 指定Observable执行任务的调度器
- doOnEach( ) — 注册一个动作,对Observable发射的每个数据项使用
- doOnCompleted( ) — 注册一个动作,对正常完成的Observable使用
- doOnError( ) — 注册一个动作,对发生错误的Observable使用
- doOnTerminate( ) — 注册一个动作,对完成的Observable使用,无论是否发生错误
- doOnSubscribe( ) — 注册一个动作,在观察者订阅时使用
- doOnUnsubscribe( ) — 注册一个动作,在观察者取消订阅时使用
- finallyDo( ) — 注册一个动作,在Observable完成时使用
- delay( ) — 延时发射Observable的结果
- delaySubscription( ) — 延时处理订阅请求
- timeInterval( ) — 定期发射数据
- using( ) — 创建一个只在Observable生命周期存在的资源
- single( ) — 强制返回单个数据,否则抛出异常
- singleOrDefault( ) — 如果Observable完成时返回了单个数据,就返回它,否则返回默认数据
- toFuture( ), toIterable( ), toList( ) — 将Observable转换为其它对象或数据结构
Delay
延迟一段指定的时间再发射来自Observable的发射物
Delay
操作符让原始Observable在发射每项数据之前都暂停一段指定的时间段。效果是Observable发射的数据项在时间上向前整体平移了一个增量。
RxJava的实现是 delay
和delaySubscription
。
第一种delay
接受一个定义时长的参数(包括数量和单位)。每当原始Observable发射一项数据,delay
就启动一个定时器,当定时器过了给定的时间段时,delay
返回的Observable发射相同的数据项。
注意:delay
不会平移onError
通知,它会立即将这个通知传递给订阅者,同时丢弃任何待发射的onNext
通知。然而它会平移一个onCompleted
通知。
delay
默认在computation
调度器上执行,你可以通过参数指定使用其它的调度器。
- Javadoc: delay(long,TimeUnit)
- Javadoc: delay()
另一种delay
不实用常数延时参数,它使用一个函数针对原始Observable的每一项数据返回一个Observable,它监视返回的这个Observable,当任何那样的Observable终止时,delay
返回的Observable就发射关联的那项数据。
这种delay
默认不在任何特定的调度器上执行。
- Javadoc: delay(Func1)
这个版本的delay
对每一项数据使用一个Observable作为原始Observable的延时定时器。
这种delay
默认不在任何特定的调度器上执行。
- Javadoc: delay(Func0,Func1)
还有一个操作符delaySubscription
让你你可以延迟订阅原始Observable。它结合搜一个定义延时的参数。
delaySubscription
默认在computation
调度器上执行,你可以通过参数指定使用其它的调度器。
- Javadoc: delaySubscription(long,TimeUnit)
- Javadoc: delaySubscription(long,TimeUnit,Scheduler)
还有一个版本的delaySubscription
使用一个Obseable而不是一个固定的时长来设置订阅延时。
这种delaySubscription
默认不在任何特定的调度器上执行。
- Javadoc: delaySubscription(Func0)
Do
注册一个动作作为原始Observable生命周期事件的一种占位符
你可以注册回调,当Observable的某个事件发生时,Rx会在与Observable链关联的正常通知集合中调用它。Rx实现了多种操作符用于达到这个目的。
RxJava实现了很多Do
操作符的变体。
doOnEach
doOnEach
操作符让你可以注册一个回调,它产生的Observable每发射一项数据就会调用它一次。你可以以Action
的形式传递参数给它,这个Action接受一个onNext
的变体Notification
作为它的唯一参数,你也可以传递一个Observable给doOnEach
,这个Observable的onNext
会被调用,就好像它订阅了原始的Observable一样。
- Javadoc: doOnEach(Action1)
- Javadoc: doOnEach(Observer)
doOnNext
doOnNext
操作符类似于doOnEach(Action1)
,但是它的Action不是接受一个Notification
参数,而是接受发射的数据项。
示例代码
Observable.just(1, 2, 3)
.doOnNext(new Action1() {
@Override
public void call(Integer item) {
if( item > 1 ) {
throw new RuntimeException( "Item exceeds maximum value" );
}
}
}).subscribe(new Subscriber() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
输出
Next: 1
Error: Item exceeds maximum value
doOnSubscribe
doOnSubscribe
操作符注册一个动作,当观察者订阅它生成的Observable它就会被调用。
- Javadoc: doOnSubscribe(Action0)
doOnUnsubscribe
doOnUnsubscribe
操作符注册一个动作,当观察者取消订阅它生成的Observable它就会被调用。
- Javadoc: doOnUnsubscribe(Action0)
doOnCompleted
doOnCompleted
操作符注册一个动作,当它产生的Observable正常终止调用onCompleted
时会被调用。
- Javadoc: doOnCompleted(Action0)
doOnError
doOnError
操作符注册一个动作,当它产生的Observable异常终止调用onError
时会被调用。
- Javadoc: doOnError(Action0)
doOnTerminate
doOnTerminate
操作符注册一个动作,当它产生的Observable终止之前会被调用,无论是正常还是异常终止。
- Javadoc: doOnTerminate(Action0)
finallyDo
finallyDo
操作符注册一个动作,当它产生的Observable终止之后会被调用,无论是正常还是异常终止。
- Javadoc: finallyDo(Action0)
Materialize/Dematerialize
Materialize
将数据项和事件通知都当做数据项发射,Dematerialize
刚好相反。
一个合法的有限的Obversable将调用它的观察者的onNext
方法零次或多次,然后调用观察者的onCompleted
或onError
正好一次。Materialize
操作符将这一系列调用,包括原来的onNext
通知和终止通知onCompleted
或onError
都转换为一个Observable发射的数据序列。
RxJava的materialize
将来自原始Observable的通知转换为Notification
对象,然后它返回的Observable会发射这些数据。
materialize
默认不在任何特定的调度器 (Scheduler
) 上执行。
- Javadoc: materialize()
Dematerialize
操作符是Materialize
的逆向过程,它将Materialize
转换的结果还原成它原本的形式。
dematerialize
反转这个过程,将原始Observable发射的Notification
对象还原成Observable的通知。
dematerialize
默认不在任何特定的调度器 (Scheduler
) 上执行。
- Javadoc: dematerialize()
ObserveOn
指定一个观察者在哪个调度器上观察这个Observable
很多ReactiveX实现都使用调度器 "Scheduler
"来管理多线程环境中Observable的转场。你可以使用ObserveOn
操作符指定Observable在一个特定的调度器上发送通知给观察者 (调用观察者的onNext
, onCompleted
, onError
方法)。
注意:当遇到一个异常时ObserveOn
会立即向前传递这个onError
终止通知,它不会等待慢速消费的Observable接受任何之前它已经收到但还没有发射的数据项。这可能意味着onError
通知会跳到(并吞掉)原始Observable发射的数据项前面,正如图例上展示的。
SubscribeOn
操作符的作用类似,但它是用于指定Observable本身在特定的调度器上执行,它同样会在那个调度器上给观察者发通知。
RxJava中,要指定Observable应该在哪个调度器上调用观察者的onNext
, onCompleted
, onError
方法,你需要使用observeOn
操作符,传递给它一个合适的Scheduler
。
- Javadoc: observeOn(Scheduler)
Serialize
强制一个Observable连续调用并保证行为正确
一个Observable可以异步调用它的观察者的方法,可能是从不同的线程调用。这可能会让Observable行为不正确,它可能会在某一个onNext
调用之前尝试调用onCompleted
或onError
方法,或者从两个不同的线程同时调用onNext
方法。使用Serialize
操作符,你可以纠正这个Observable的行为,保证它的行为是正确的且是同步的。
RxJava中的实现是serialize
,它默认不在任何特定的调度器上执行。
- Javadoc: serialize()
Subscribe
操作来自Observable的发射物和通知
Subscribe
操作符是连接观察者和Observable的胶水。一个观察者要想看到Observable发射的数据项,或者想要从Observable获取错误和完成通知,它首先必须使用这个操作符订阅那个Observable。
Subscribe
操作符的一般实现可能会接受一到三个方法(然后由观察者组合它们),或者接受一个实现了包含这三个方法的接口的对象(有时叫做Observer
或Subscriber
):
onNext
每当Observable发射了一项数据它就会调用这个方法。这个方法的参数是这个Observable发射的数据项。
onError
Observable调用这个方法表示它无法生成期待的数据或者遇到了其它错误。这将停止Observable,它在这之后不会再调用onNext
或onCompleted
。onError
方法的参数是导致这个错误的原因的一个表示(有时可能是一个Exception或Throwable对象,其它时候也可能是一个简单的字符串,取决于具体的实现)。
onCompleted
如果没有遇到任何错误,Observable在最后一次调用onCompleted
之后会调用这个方法。
如果一个Observable直到有一个观察者订阅它才开始发射数据项,就称之为"冷"的Observable;如果一个Observable可能在任何时刻开始发射数据,就称之为"热"的Observable,一个订阅者可能从开始之后的某个时刻开始观察它发射的数据序列,它可能会错过在订阅之前发射的数据。
RxJava中的实现是subscribe
方法。
如果你使用无参数的版本,它将触发对Observable的一个订阅,但是将忽略它的发射物和通知。这个操作会激活一个"冷"的Observable。
你也可以传递一到三个函数给它,它们会按下面的方法解释:
onNext
-
onNext
和onError
-
onNext
,onError
和onCompleted
最后,你还可以传递一个Observer
或Subscriber
接口给它,Observer
接口包含这三个以on
开头的方法。Subscriber
接口也实现了这三个方法,而且还添加了几个额外的方法,用于支持使用反压操作(reactive pull backpressure
),这让Subscriber
可以在Observable完成前取消订阅。
subscribe
方法返回一个实现了Subscription
接口的对象。这个接口包含unsubscribe
方法,任何时刻你都可以调用它来断开subscribe
方法建立的Observable和观察者之间的订阅关系。
- Javadoc: subscribe()
- Javadoc: subscribe(Action1)
- Javadoc: subscribe(Action1,Action1)
- Javadoc: subscribe(Action1,Action1,Action0)
- Javadoc: subscribe(Observer)
- Javadoc: subscribe(Subscriber)
foreach
forEach
方法是简化版的subscribe
,你同样可以传递一到三个函数给它,解释和传递给subscribe
时一样。
不同的是,你无法使用forEach
返回的对象取消订阅。也没办法传递一个可以用于取消订阅的参数。因此,只有当你明确地需要操作Observable的所有发射物和通知时,你才应该使用这个操作符。
- Javadoc: forEach(Action1)
- Javadoc: forEach(Action1,Action1)
- Javadoc: forEach(Action1,Action1,A/Users/mcxiaoke/github/RxDocs/docs/BlockingObservable.mdction0)
BlockingObservable
BlockingObservable
类中也有一个类似的叫作forEach
的方法。详细的说明见 BlockingObservable
SubscribeOn
指定Observable自身在哪个调度器上执行
很多ReactiveX实现都使用调度器 "Scheduler
"来管理多线程环境中Observable的转场。你可以使用SubscribeOn
操作符指定Observable在一个特定的调度器上运转。
ObserveOn
操作符的作用类似,但是功能很有限,它指示Observable在一个指定的调度器上给观察者发通知。
在某些实现中还有一个UnsubscribeOn
操作符。
- Javadoc: subscribeOn(Scheduler)
- Javadoc: unsubscribeOn(Scheduler)
TimeInterval
将一个发射数据的Observable转换为发射那些数据发射时间间隔的Observable
TimeInterval
操作符拦截原始Observable发射的数据项,替换为发射表示相邻发射物时间间隔的对象。
RxJava中的实现为timeInterval
,这个操作符将原始Observable转换为另一个Observable,后者发射一个标志替换前者的数据项,这个标志表示前者的两个连续发射物之间流逝的时间长度。新的Observable的第一个发射物表示的是在观察者订阅原始Observable到原始Observable发射它的第一项数据之间流逝的时间长度。不存在与原始Observable发射最后一项数据和发射onCompleted
通知之间时长对应的发射物。
timeInterval
默认在immediate
调度器上执行,你可以通过传参数修改。
- Javadoc: timeInterval()
- Javadoc: timeInterval(Scheduler)
Timeout
对原始Observable的一个镜像,如果过了一个指定的时长仍没有发射数据,它会发一个错误通知
如果原始Observable过了指定的一段时长没有发射任何数据,Timeout
操作符会以一个onError
通知终止这个Observable。
RxJava中的实现为timeout
,但是有好几个变体。
第一个变体接受一个时长参数,每当原始Observable发射了一项数据,timeout
就启动一个计时器,如果计时器超过了指定指定的时长而原始Observable没有发射另一项数据,timeout
就抛出TimeoutException
,以一个错误通知终止Observable。
这个timeout
默认在computation
调度器上执行,你可以通过参数指定其它的调度器。
- Javadoc: timeout(long,TimeUnit)
- Javadoc: timeout()
这个版本的timeout
在超时时会切换到使用一个你指定的备用的Observable,而不是发错误通知。它也默认在computation
调度器上执行。
- Javadoc: timeout(long,TimeUnit,Observable)
- Javadoc: timeout(long,TimeUnit,Observable,Scheduler)
这个版本的timeout
使用一个函数针对原始Observable的每一项返回一个Observable,如果当这个Observable终止时原始Observable还没有发射另一项数据,就会认为是超时了,timeout
就抛出TimeoutException
,以一个错误通知终止Observable。
这个timeout
默认在immediate
调度器上执行。
- Javadoc: timeout(Func1)
这个版本的timeout
同时指定超时时长和备用的Observable。它默认在immediate
调度器上执行。
- Javadoc: timeout(Func1,Observable)
这个版本的time
除了给每一项设置超时,还可以单独给第一项设置一个超时。它默认在immediate
调度器上执行。
- Javadoc: timeout(Func0,Func1)
同上,但是同时可以指定一个备用的Observable。它默认在immediate
调度器上执行。
- Javadoc: timeout(Func0,Func1,Observable)
Timestamp
给Observable发射的数据项附加一个时间戳
RxJava中的实现为timestamp
,它将一个发射T类型数据的Observable转换为一个发射类型为Timestamped
的数据的Observable,每一项都包含数据的原始发射时间。
timestamp
默认在immediate
调度器上执行,但是可以通过参数指定其它的调度器。
- Javadoc: timestamp()
- Javadoc: timestamp(Scheduler)
Using
创建一个只在Observable生命周期内存在的一次性资源
Using
操作符让你可以指示Observable创建一个只在它的生命周期内存在的资源,当Observable终止时这个资源会被自动释放。
using
操作符接受三个参数:
- 一个用户创建一次性资源的工厂函数
- 一个用于创建Observable的工厂函数
- 一个用于释放资源的函数
当一个观察者订阅using
返回的Observable时,using
将会使用Observable工厂函数创建观察者要观察的Observable,同时使用资源工厂函数创建一个你想要创建的资源。当观察者取消订阅这个Observable时,或者当观察者终止时(无论是正常终止还是因错误而终止),using
使用第三个函数释放它创建的资源。
using
默认不在任何特定的调度器上执行。
- Javadoc: using(Func0,Func1,Action1)
To
将Observable转换为另一个对象或数据结构
ReactiveX的很多语言特定实现都有一种操作符让你可以将Observable或者Observable发射的数据序列转换为另一个对象或数据结构。它们中的一些会阻塞直到Observable终止,然后生成一个等价的对象或数据结构;另一些返回一个发射那个对象或数据结构的Observable。
在某些ReactiveX实现中,还有一个操作符用于将Observable转换成阻塞式的。一个阻塞式的Ogbservable在普通的Observable的基础上增加了几个方法,用于操作Observable发射的数据项。
getIterator
getIterator
操作符只能用于BlockingObservable
的子类,要使用它,你首先必须把原始的Observable转换为一个BlockingObservable
。可以使用这两个操作符:BlockingObservable.from
或the Observable.toBlocking
。
这个操作符将Observable转换为一个Iterator
,你可以通过它迭代原始Observable发射的数据集。
- Javadoc: BlockingObservable.getIterator()
toFuture
toFuture
操作符也是只能用于BlockingObservable
。这个操作符将Observable转换为一个返回单个数据项的Future
,如果原始Observable发射多个数据项,Future
会收到一个IllegalArgumentException
;如果原始Observable没有发射任何数据,Future
会收到一个NoSuchElementException
。
如果你想将发射多个数据项的Observable转换为Future
,可以这样用:myObservable.toList().toBlocking().toFuture()
。
- Javadoc: BlockingObservable.toFuture()
toIterable
toFuture
操作符也是只能用于BlockingObservable
。这个操作符将Observable转换为一个Iterable
,你可以通过它迭代原始Observable发射的数据集。
- Javadoc: BlockingObservable.toIterable()
toList
通常,发射多项数据的Observable会为每一项数据调用onNext
方法。你可以用toList
操作符改变这个行为,让Observable将多项数据组合成一个List
,然后调用一次onNext
方法传递整个列表。
如果原始Observable没有发射任何数据就调用了onCompleted
,toList
返回的Observable会在调用onCompleted
之前发射一个空列表。如果原始Observable调用了onError
,toList
返回的Observable会立即调用它的观察者的onError
方法。
toList
默认不在任何特定的调度器上执行。
- Javadoc: toList()
toMap
toMap
收集原始Observable发射的所有数据项到一个Map(默认是HashMap)然后发射这个Map。你可以提供一个用于生成Map的Key的函数,还可以提供一个函数转换数据项到Map存储的值(默认数据项本身就是值)。
toMap
默认不在任何特定的调度器上执行。
- Javadoc: toMap(Func1)
- Javadoc: toMap(Func1,Func1)
- Javadoc: toMap(Func1,Func1,Func0)
toMultiMap
toMultiMap
类似于toMap
,不同的是,它生成的这个Map同时还是一个ArrayList
(默认是这样,你可以传递一个可选的工厂方法修改这个行为)。
toMultiMap
默认不在任何特定的调度器上执行。
- Javadoc: toMultiMap(Func1)
- Javadoc: toMultiMap(Func1,Func1)
- Javadoc: toMultiMap(Func1,Func1,Func0)
- Javadoc: toMultiMap(Func1,Func1,Func0,Func1)
toSortedList
toSortedList
类似于toList
,不同的是,它会对产生的列表排序,默认是自然升序,如果发射的数据项没有实现Comparable
接口,会抛出一个异常。然而,你也可以传递一个函数作为用于比较两个数据项,这是toSortedList
不会使用Comparable
接口。
toSortedList
默认不在任何特定的调度器上执行。
- Javadoc: toSortedList()
- Javadoc: toSortedList(Func2)
Rxjava操作符五