@cxm-2016
2016-12-01T22:10:03.000000Z
字数 10690
阅读 3663
RxJava学习指南
版本:5
整理:陈小默
使用一个函数从头开始创建一个Observable
你可以使用Create
操作符从头开始创建一个Observable。
其中的onComplete或onError只能被执行一个并且只能被执行一次。
RxJava将这个操作符实现为 create
方法。
建议你在传递给create
方法的函数中检查观察者的isUnsubscribed
状态,以便在没有观察者的时候,让你的Observable停止发射数据或者做复杂的运算。
示例代码:
Observable.create<Int> {
with(it) {
if (!isUnsubscribed) {
try {
for (i in 1 until 5) onNext(i)
onCompleted()
} catch (e: Exception) {
onError(e)
}
}
}
}.subscribe(
{ println("Next: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
输出:
Next: 1
Next: 2
Next: 3
Next: 4
Sequence complete.
create
方法默认不在任何特定的调度器上执行。
直到有观察者订阅时才创建Observable,并且为每个观察者创建一个新的Observable
Defer
操作符会一直等待直到有观察者订阅它,然后它使用Observable工厂方法生成一个Observable。它对每个观察者都这样做,因此尽管每个订阅者都以为自己订阅的是同一个Observable,事实上每个订阅者获取的是它们自己的单独的数据序列。
在某些情况下,等待直到最后一分钟(就是知道订阅发生时)才生成Observable可以确保Observable包含最新的数据。
RxJava将这个操作符实现为 defer
方法。这个操作符接受一个你选择的Observable工厂函数作为单个参数。这个函数没有参数,返回一个Observable。
defer
方法默认不在任何特定的调度器上执行。
示例程序:
val key = "暴走"
val defer = Observable.defer {
Observable.create<List<News>> {
with(it) {
if (!isUnsubscribed) {
try {
onNext(query(key))
onCompleted()
} catch (e: Exception) {
onError(e)
}
}
}
}
}
defer.subscribe(
{ println("List size: ${it.size}") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
可选包 rxjava-computation-expressions
中有一个类似的操作符。switchCase
操作符有条件的创建并返回一个可能的Observables集合中的一个。
val statement = mapOf<Int, Observable<Int>>(
0 to Observable.from(arrayOf(1, 2, 3)),
1 to Observable.from(arrayOf(7, 8, 9)))
Statement.switchCase({ param }, statement).subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
运行结果
param = 0时:
Item: 1
Item: 2
Item: 3
Sequence complete
param = 1时:
Item: 7
Item: 8
Item: 9
Sequence complete
可选包 rxjava-computation-expressions
中还有一个更简单的操作符叫ifThen
。这个操作符检查某个条件,然后根据结果,返回原始Observable的镜像,或者返回一个空Observable。
Statement.ifThen({ param }, Observable.from(arrayOf(1, 2, 3)))
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
输出结果
param = true时
Item: 1
Item: 2
Item: 3
Sequence complete
param = false时
Sequence complete
创建一个不发射任何数据但是正常终止的Observable
示例程序
Observable.empty<Int>().subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") }
)
输出结果
equence complete
创建一个不发射数据也不终止的Observable
示例程序
Observable.never<Int>().subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") }
)
该程序不会有任何输出
创建一个不发射数据以一个错误终止的Observable
示例代码
Observable.error<Int>(RuntimeException()).subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") }
)
将其它种类的对象和数据类型转换为Observable
当你使用Observable时,如果你要处理的数据都可以转换成展现为Observables,而不是需要混合使用Observables和其它类型的数据,会非常方便。这让你在数据流的整个生命周期中,可以使用一组统一的操作符来管理它们。
例如,Iterable可以看成是同步的Observable;Future,可以看成是总是只发射单个数据的Observable。通过显式地将那些数据转换为Observables,你可以像使用Observable一样与它们交互。
因此,大部分ReactiveX实现都提供了将语言特定的对象和数据结构转换为Observables的方法。
在RxJava中,from
操作符可以转换Future、Iterable和数组。对于Iterable和数组,产生的Observable会发射Iterable或数组的每一项数据。
示例代码
Observable.from(arrayOf(1, 2, 3)).subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
输出
Item: 1
Item: 2
Item: 3
Sequence complete
对于Future,它会发射Future.get()方法返回的单个数据。from
方法有一个可接受两个可选参数的版本,分别指定超时时长和时间单位。如果过了指定的时长Future还没有返回一个值,这个Observable会发射错误通知并终止。
from
默认不在任何特定的调度器上执行。然而你可以将Scheduler作为可选的第二个参数传递给Observable,它会在那个调度器上管理这个Future。
此外,在可选包 RxJavaAsyncUtil
中,你还可以用下面这些操作符将actions,callables,functions和runnables转换为发射这些动作的执行结果的Observable:
在这个页面 Start 查看关于这些操作符的更多信息。
注意:还有一个可选的StringObservable
类中也有一个from
方法,它将一个字符流或者一个REader转换为一个发射字节数组或字符串的Observable。
注意:这里与后面start
操作符里的runAsync
说明重复了
在单独的RxJavaAsyncUtil
包中(默认不包含在RxJava中),还有一个runAsync
函数。传递一个Action
和一个Scheduler
给runAsync
,它会返回一个StoppableObservable
,这个Observable使用Action
产生发射的数据项。
传递一个Action
和一个Scheduler
给runAsync
,它返回一个使用这个Action
产生数据的StoppableObservable
。这个Action
接受一个Observable
和一个Subscription
作为参数,它使用Subscription
检查unsubscribed
条件,一旦发现条件为真就立即停止发射数据。在任何时候你都可以使用unsubscribe
方法手动停止一个StoppableObservable
(这会同时取消订阅与这个StoppableObservable
关联的Subscription
)。
由于runAsync
会立即调用Action
并开始发射数据,在你创建StoppableObservable之后到你的观察者准备好接受数据之前这段时间里,可能会有一部分数据会丢失。如果这不符合你的要求,可以使用runAsync
的一个变体,它也接受一个Subject
参数,传递一个ReplaySubject
给它,你可以获取其它丢失的数据了。
StringObservable
类不是默认RxJava的一部分,包含一个decode
操作符,这个操作符将一个多字节字符流转换为一个发射字节数组的Observable,这些字节数组按照字符的边界划分。
Interval
操作符创建的Observable每隔固定时间发射一个从0起递增的Long型整数。
以下重载增加了一个延时属性。
Javadoc: interval(long,long,TimeUnit)
Javadoc: interval(long,long,TimeUnit,Scheduler)
interval
默认在computation
调度器上执行
创建一个发射指定值的Observable
与From不同,Just将每个数据都转换为一个只发射一个数据的Observable。
RxJava将这个操作符实现为just
函数,它接受一至九个参数,返回一个按参数列表顺序发射这些数据的Observable。
示例代码:
Observable.just(1, 2, 3).subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
输出
Item: 1
Item: 2
Item: 3
Sequence complete
创建一个发射特定整数序列的Observable
创建一个Observable,这个Observable会从n开始发射递增的m个数据。如果m为负数,会抛出异常。
range
默认不在任何特定的调度器上执行
示例代码:
Observable.range(1,3).subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
运行结果
Item: 1
Item: 2
Item: 3
Sequence complete
创建一个发射特定数据重复多次的Observable
Repeat重复地发射数据。某些实现允许你重复的发射某个数据序列,还有一些允许你限制重复的次数。
RxJava将这个操作符实现为repeat
方法。它不是创建一个Observable,而是重复发射原始Observable的数据序列,这个序列或者是无限的,或者通过repeat(n)
指定重复次数。
repeat
操作符默认在trampoline
调度器上执行。有一个变体可以通过可选参数指定Scheduler。
Javadoc: repeat()
Javadoc: repeat(long)
示例代码:
Observable.from(arrayOf(1, 2, 3)).repeat(2)
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
结果
Item: 1
Item: 2
Item: 3
Item: 1
Item: 2
Item: 3
Sequence complete
Javadoc: repeat(Scheduler)
Javadoc: repeat(long,Scheduler)
还有一个叫做repeatWhen
的操作符,它不是缓存和重放原始Observable的数据序列,而是有条件的重新订阅和发射原来的Observable。
将原始Observable的终止通知(完成或错误)当做一个void
数据传递给一个通知处理器,它以此来决定是否要重新订阅和发射原来的Observable。这个通知处理器就像一个Observable操作符,接受一个发射void
通知的Observable为输入,返回一个发射void
数据(意思是,重新订阅和发射原始Observable)或者直接终止(意思是,使用repeatWhen
终止发射数据)的Observable。
repeatWhen
操作符默认在trampoline
调度器上执行。有一个变体可以通过可选参数指定Scheduler。
doWhile
属于可选包rxjava-computation-expressions
,不是RxJava标准操作符的一部分。doWhile
在原始序列的每次重复后检查某个条件,如果满足条件才重复发射。
Statement.doWhile(Observable.just(1, 2, 3), { param })
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
先循环后判断param
whileDo
属于可选包rxjava-computation-expressions
,不是RxJava标准操作符的一部分。whileDo
在原始序列的每次重复前检查某个条件,如果满足条件才重复发射。
Statement.whileDo(Observable.just(1, 2, 3), { param })
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
先判断param再循环
返回一个Observable,它发射一个类似于函数声明的值
编程语言有很多种方法可以从运算结果中获取值,它们的名字一般叫functions, futures, actions, callables, runnables
等等。在Start
目录下的这组操作符可以让它们表现得像Observable,因此它们可以在Observables调用链中与其它Observable搭配使用。
Start
操作符的多种RxJava实现都属于可选的rxjava-async
模块。
rxjava-async
模块包含start
操作符,它接受一个函数作为参数,调用这个函数获取一个值,然后返回一个会发射这个值给后续观察者的Observable。
注意:这个函数只会被执行一次,即使多个观察者订阅这个返回的Observable。
fun func(x: Int, y: Int) = x + y
Async.start { func(a, b) }
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
当a=1,b=2时,返回结果如下
Item: 3
Sequence complete
rxjava-async
模块还包含这几个操作符:toAsync
, asyncAction
, 和asyncFunc
。它们接受一个函数或一个Action作为参数。
对于函数(functions),这个操作符调用这个函数获取一个值,然后返回一个会发射这个值给后续观察者的Observable(和start
一样)。对于动作(Action),过程类似,但是没有返回值,在这种情况下,这个操作符在终止前会发射一个null
值。
注意:这个函数或动作只会被执行一次,即使多个观察者订阅这个返回的Observable。
rxjava-async
模块还包含一个startFuture
操作符,传递给它一个返回Future
的函数,startFuture
会立即调用这个函数获取Future
对象,然后调用Future
的get()
方法尝试获取它的值。它返回一个发射这个值给后续观察者的Observable。
val future : Future<Int>
Async.startFuture { future }.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
rxjava-async
模块还包含一个deferFuture
操作符,传递给它一个返回Future
的函数(这个Future
返回一个Observable
),deferFuture
返回一个Observable,但是不会调用你提供的函数,直到有观察者订阅它返回的Observable。这时,它立即调用Future
的get()
方法,然后镜像发射get()
方法返回的Observable发射的数据。
用这种方法,你可以在Observables调用链中包含一个返回Observable的Future
对象。
val future : Future<Observable<Int>>
Async.deferFuture { future }.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
rxjava-async
模块还包含一个fromAction
操作符,它接受一个Action
作为参数,返回一个Observable,一旦Action终止,它发射这个你传递给fromAction
的数据。
Async.fromAction({
println("action")
}, 1)
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
rxjava-async
模块还包含一个fromCallable
操作符,它接受一个Callable
作为参数,返回一个发射这个Callable
的结果的Observable。
Async.fromCallable { 1 }
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
rxjava-async
模块还包含一个fromRunnable
操作符,它接受一个Runnable
作为参数,返回一个Observable,一旦Runnable终止,它发射这个你传递给fromRunnable
的数据。
Async.fromRunnable({
for (i in 0 until 10) println(i)
}, 1)
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
上述程序会在循环结束后发射数据
rxjava-async
模块还包含一个forEachFuture
操作符。它其实不算Start
操作符的一个变体,而是有一些自己的特点。你传递一些典型的观察者方法(如onNext, onError和onCompleted)给它,Observable会以通常的方式调用它。但是forEachFuture
自己返回一个Future
并且在get()
方法处阻塞,直到原始Observable执行完成,然后它返回,完成还是错误依赖于原始Observable是完成还是错误。
如果你想要一个函数阻塞直到Observable执行完成,可以使用这个操作符。
Async.forEachFuture(Observable.just(1,2,3),
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })
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
相似。
创建一个Observable,它在一个给定的延迟后发射一个0。
timer
返回一个Observable,它在延迟一段给定的时间后发射一个简单的数字0。
timer
操作符默认在computation
调度器上执行。有一个变体可以通过可选参数指定Scheduler。
Observable.timer(1000L, TimeUnit.MILLISECONDS, Schedulers.immediate())
.subscribe(
{ println("Item: $it") },
{ println("Error: ${it.message}") },
{ println("Sequence complete") })