2017-06-08 | Android android, reactive-streams, rxjava
上篇说到RxJava给我们提供各种操作符来处理日常处理操作,今天我们来详细分析下各种操作符的作用和用法。为此我之前花了点时间增加了博文的目录导航功能,方便大家查阅时候使用。
由于本文主要讲述操作符作用,本文使用lambda表达式来简化代码,如果不熟悉lambda的读者可以参考我之前的文章,如果涉及前文没有提到的类会不使用lambdb来表示。
首先回想一下第一篇中说到的被观察者可以采用Flowable、Observable、Single等等的create方法来实现,如果对于只是发送几个数据来说,这个过程未免十分复杂繁琐,可以使用just操作符来简化:
Flowable.just("test","test2")
.subscribe(str -> Log.i("tag", str));
上述代码相当于顺序调用onNext("test")
和onNext("test2")
,然后调用onComplete方法。
另外还可以使用Observable、Single或者Maybe来调用这个操作符。对于Completable则不能使用(因为没有onNext事件),对于Flowable和Observable最多能接收10个参数,也就是发送10个数据,而Single和Maybe只能接收1个参数(只能发送一次onNext事件)。这些都是理解了本质就能明白为什么会这样,所以下面的操作符非特殊情况就不再一一说明各种被观察者使用区别。
之前说到的just操作符,最多只能接收10个参数。我们通过观察just操作符的源码发现,其实超过2个参数时,它会帮我们调用fromArray操作符,采用fromArray来接收任意长度的数据数组,下面来举个例子说明:
Flowable.fromArray(1, 2, 3, 4, 5)
.subscribe(integer -> Log.i("tag", String.valueOf(integer)));
fromArray可以直接传入一个数组,例如fromArray(new int[]{1, 2, 3})
,但是不要直接传递一个list进去,这样它会直接把list当做一个数据元素发送。
上面说到,fromArray可以接受任意长度的数据数组,假设数组元素数量为0会怎么样呢?我们查看fromArray源代码,可以发现,当数据长度为0时,会调用empty操作符。
empty操作符不会发送任何数据,而是直接发送onComplete事件,我们写一个例子:
Flowable.empty().subscribe(
obj -> Log.i("tag", "next" + obj.toString()),
e -> Log.i("tag", "error"),
() -> Log.i("tag", "complete"));
会发现上面的例子只会打印complete,其他回调并不会触发。
除了直接发送onComplete,当然就有直接发送onError,error操作符就是调用时候直接发送onError事件给观察者:
Flowable.error(new RuntimeException("test")).subscribe(
obj -> Log.i("tag", "next" + obj.toString()),
e -> Log.i("tag", "error"),
() -> Log.i("tag", "complete"));
上面的例子将只会打印error,其他回调并不会触发。
下面来介绍另外一个什么都不会发送的操作符never,也不会触发观察者任何的回调:
Flowable.never().subscribe(
obj -> Log.i("tag", "next" + obj.toString()),
e -> Log.i("tag", "error"),
() -> Log.i("tag", "complete"));
上面的例子将不会输出任何东西,这个操作符通常用于“测试”用途。
上文说到的fromArray并不能遍历list等集合,采用fromIterable可以遍历可迭代数据集合:
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
Flowable.fromIterable(list).subscribe(
s -> Log.i("tag", s)
);
可以看到输出结果是顺序输出列表中的元素,fromIterable和fromArray除了输入数据不同,其他基本是相似的。
接下来我们说一下时间间隔操作符timer,可以指定一段时间发送数据(固定值0L):
Flowable.timer(1, TimeUnit.SECONDS)
//这里的x是long类型
.subscribe(x -> Log.i("tag", String.valueOf(x)));
上面例子为延迟1秒后调用onNext(0)
,然后调用onComplete()
事件。其中timer操作符还有重载方法可以接受多一个参数Scheduler,这个后面会介绍到。
上面的timer操作符只能发送一次数据,对于要不断地发送数据,可以采用interval操作符:
Flowable.interval(2, 1, TimeUnit.SECONDS)
//这里的x是0,1,2,3...
.subscribe(x -> Log.i("tag", String.valueOf(x)));
这里interval接受的第一个参数是第一次的延迟,如果忽略(重载方法)则和设定的间隔一样,也可以单独设置Scheduler。
如果你运行了上面的代码,会发现interval操作符会无限执行,永不停止,那么应该怎么停止呢?这里就需要过滤操作符take了,为避免打乱文章顺序,这个也是后面再详细介绍。
上面说到interval操作符是从0开始发送数据,如果我们需要指定发送范围,那么可以使用intervalRange操作符:
Flowable.intervalRange(1, 10, 2, 1, TimeUnit.SECONDS)
//x从1-10,初始间隔2秒,之后间隔1秒发送一次
.subscribe(x -> Log.i("tag", String.valueOf(x)));
如同注释中的说明,当x从1开始发送到10后(注意参数10是发送10个数量的意思,类似于request(10)的操作)调用onComplete方法,值得注意的是从最后一个元素发出到onComplete之间并不会有period长度的延迟。
如果你不需要延迟发送数据,但是需要确定一个数据的范围可以采用range或者是rangeLong,后者的数据类型是long,可以使用的范围更加广,其他完全是一样的,其用法如下:
//int类型范围
Flowable.range(0, 5)
.subscribe(x -> Log.i("tag", String.valueOf(x)));
//long类型范围
Flowable.rangeLong(Integer.MAX_VALUE, 5L)
.subscribe(x -> Log.i("tag", String.valueOf(x)));
上述输出都是从第一个数开始直接输出到最后一个数(第二个参数也是数量,而不是尾数)然后调用onComplete事件,中间没有间隔延迟。
之前说过一个被观察者可以订阅多个观察者,如果需要每个观察者被订阅的时候都重新创建被观察者(一对一),则可以使用defer操作符:
Flowable<String> flowable = Flowable.defer(new Callable<Publisher<String>>() {
@Override
public Publisher<String> call() throws Exception {
return Flowable.just("1", "2");
}
});
//订阅第一个观察者
flowable.subscribe(str -> Log.i("tag", str));
//订阅第二个观察者
flowable.subscribe(str -> Log.i("tag", str));
上面会输出两次(1,2)而且是顺序输出,只有当第一个观察者执行完后才回去创建第二个被观察者然后订阅观察者,然后才开始(第二个被观察者)发送事件消息。
上文主要介绍了RxJava中的常用创建操作符,本来打算一篇写完全部操作符,但是写着写着发现篇幅已经过长,于是重新整理了一下,对操作符也分下类,方便阅读,下篇继续详解更多的操作符。
RxJava 2.x 使用详解(一) 快速入门: https://maxwell-nc.github.io/android/rxjava2-1.html
RxJava 2.x 使用详解(二) 创建操作符: https://maxwell-nc.github.io/android/rxjava2-2.html
RxJava 2.x 使用详解(三) 过滤操作符: https://maxwell-nc.github.io/android/rxjava2-3.html
RxJava 2.x 使用详解(四) 合并聚合操作符: https://maxwell-nc.github.io/android/rxjava2-4.html
RxJava 2.x 使用详解(五) 条件操作符: https://maxwell-nc.github.io/android/rxjava2-5.html
RxJava 2.x 使用详解(六) 变换操作符: https://maxwell-nc.github.io/android/rxjava2-6.html
原创文章,欢迎转载,请保留出处。有任何错误、疑问或者建议,欢迎指出。
请注明文章出自于:https://maxwell-nc.github.io/android/rxjava2-2.html