概述
在前文RxJava2操作符之map中记录了map
的使用方法及场景,而日常开发中除了map,flatMap以及concatMap使用的也比较多,那这篇文章就记录一下这两个操作符的情况。
RxJava2操作符之map中介绍了一些基础知识以及学习方法,强烈建议先大体浏览一下。
flatMap
使用场景
第一:比较典型的就是可以使用flatMap解决嵌套回调的问题,例如我们有两个API,A和B,B的调用需要A的返回结果作为参数,如果以回调的方式来完成的话,我们需要在A的callback中发起B的调用,然后在B的callback中处理返回结果。
第二:凡是需要map,而变换后需要一个Observable的场景下均可以考虑。
使用说明
官方解释:
Returns an Observable that emits items based on applying a function that you supply to each item emitted by the source ObservableSource, where that function returns an ObservableSource, and then merging those resulting, ObservableSources and emitting the results of this merger.
前半部分与map操作符一致,会对原始发射的每个数据进行转换,但是与map不同的是flatMap对每一个数据项转换后的结果是一个Observable。这些转换后得到的Observable会被合并在一起后由一个统一的Observable分别发射这个集合体的事件。
解释过于抽象,请看下图:
上面3个圆圈经过中间的flatMap
变成了下面的6个菱形。为什么是6个呢,因为图中的flatMap
将1个圆圈变成2个菱形。如果faltMap
的规则是将1个圆圈变为1个菱形,那么最终就是3个菱形了,这个由我们使用者决定。还有值得注意的一点就是,下面的绿色菱形和蓝色凌的顺序交叉了,而不是按照2个红色,2个绿色,2个蓝色的顺序来的。这说明flatMap
变换后发射数据的顺序是不可预测的,这一点要注意。
Observable.range(1,3)
.flatMap(new Function<Integer, ObservableSource<String>>()
{
@Override
public ObservableSource<String> apply(final Integer integer) throws Exception
{
return Observable.create(new ObservableOnSubscribe<String>()
{
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext(String.format("第%s个数据的第1个转换",integer));
emitter.onNext(String.format("第%s个数据的第2个转换",integer));
emitter.onComplete();
}
}).subscribeOn(Schedulers.newThread());
}
}).subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d("FlatMap",s);
}
});
上面的代码是将1,2,3三个数据源分别使用flatMap
作了变换, 得到3个Observable
,而在每一个Observable
中又分别发射了两个变换后的数据,那总共就是6条数据。
输出结果:
第一次执行:
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第1个数据的第1个转换
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第2个数据的第1个转换
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第2个数据的第2个转换
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第3个数据的第1个转换
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第3个数据的第2个转换
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第1个数据的第2个转换
第二次执行:
2018-10-21 19:07:15.185 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第3个数据的第1个转换
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第3个数据的第2个转换
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第1个数据的第1个转换
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第1个数据的第2个转换
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第2个数据的第1个转换
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第2个数据的第2个转换
从输出结果可以看到,6个数据项到达观察端的顺序是不固定的,由每个的发射顺序和执行时间一起决定。发射的早而耗时又少的肯定是首先到达,那些发射晚而耗时又长的肯定是最后到达。
那么遇到需要按照发射顺序而获得到达顺序时怎么办呢?conactMap
就闪亮登场了!
conactMap
官方解释
Returns a new Observable that emits items resulting from applying a function that you supply to each item emitted by the source ObservableSource, where that function returns an ObservableSource, and then emitting the items that result from concatenating those resulting ObservableSources.
从上图可知,conactMap 与flatMap唯一的区别就是接收的数据是与发射数据的顺序一致。
将上面代码中的flatMap换为conactMap,然后看一下输出结果:
Observable.range(1,3)
.concatMap(new Function<Integer, ObservableSource<String>>() {
...
}).subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d("ConcatMap",s);
}
});
输出结果:
第一次输出:
2018-10-21 19:22:13.449 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第1个数据的第1个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第1个数据的第2个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第2个数据的第1个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第2个数据的第2个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第3个数据的第1个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第3个数据的第2个转换
第二次输出:
2018-10-21 19:22:13.449 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第1个数据的第1个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第1个数据的第2个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第2个数据的第1个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第2个数据的第2个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第3个数据的第1个转换
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第3个数据的第2个转换
可见多次执行后输出结果是稳定的。
总结
Talk is cheap,show me the picture, 真是一图胜前言啊!希望大家再遇到不熟悉的rxjava2的操作符,先看一下那个配图。