前言:
本篇基于Map操作符,阅读该篇请确保,你已经了解过它:RxJava2 转换操作符之Map()方法。一如既往,干大事的人都是直接先上图,再解释的。(建议用PC端阅读,图片可以放大。排版,也有利于阅读)

二、FlatMap的操作流程图解
先来跟你讲讲,这图咋看。这上面的线,表示原始数据。下面的线,表示转换后的数据。中间的块,代表转换过程。两条线的结尾有一小条竖线,表示结束。箭头的方向,从左到右,表示运行过程,是从左到右跑的。

1、(Question-1)你可能会奇怪,为毛从左到右数,第5个会是绿色的,不应该也是蓝色的吗?
这个,得分成多步解释,请耐心一下:

  1. 圆与棱形是一对多的关系。即一个圆既可以转换成一个棱形,也可以转换成多个棱形。该图解,以每1个圆都对应2个棱形为例。那么,可不可以第1个圆对应2个棱形,第2个圆对应3个棱形,第3个圆对应x个棱形呢?当然可以!
  2. FlatMap的Flat是铺平的意思。即先将所有圆转成棱形,比如例子中,是先将3个圆转成6个棱形。然后,再一 一开始对它们进行转换,看图(… 找个时间得学一下ps才行, 图有点粗糙,但理不糙):

    虽然,是从左到右开始执行任务。但谁先执行完,谁就先返回。就跟跑步一样,虽然有人先跑,但未必他就是先到终点的。
  3. 圆是一级任务,每一个一级任务包含多个二级子任务。子任务,即是棱形。

2、(Question-2)不是说,一个一个执行吗?那怎么会出现交叉(就是两蓝中插了个一绿的)呢?
因为,不同的二级任务的执行时间是不同的。比方说:第一个绿色棱形的任务是计算:1+1。第二个绿色的棱形任务是:从服务器获取用户信息和系统配置。第一个蓝色棱形的任务是计算:2+2。第二个蓝色的棱形任务是:做特别复杂耗时的操作,比第二个绿色的棱形的任务执行的还要久。那么,从例子可以看出。第一个绿色棱形肯定是先完成。但第二个绿色棱形的任务,执行的时间肯定比,第一个蓝色棱形的任务还要久。所以,就会出现,先出现第一个蓝色棱形,后再出现第二个绿色的棱形。。。

三、少跟我说理论!上代码,要复制就能跑,一眼就看得懂的。
答:… 先喝点加多宝,我这就上代码。

    public static void actionFlatMap() {List<Integer> list = Arrays.asList(1, 2, 3);// 这里用了lambda。Observable.fromIterable(list).flatMap(integer -> {log("开始执行,第" + integer + "圆球的任务" + getThreadName());return getObservable(integer);}).subscribe(s -> log("已完成" + s + getThreadName()));}public static Observable<String> getObservable(final int integer) {return Observable.create((ObservableOnSubscribe<String>) emitter -> {emitter.onNext("第" + integer + "圆球的第1个棱形任务");if(integer != 1) {// 第2和第3个圆球的第二个任务延时。Thread.sleep(5 * 1000);}emitter.onNext("第" + integer + "圆球的第2个棱形任务");emitter.onComplete();}).subscribeOn(Schedulers.newThread());}// 返回当前的线程名public static String getThreadName() {return "  |  ThreadName=" + Thread.currentThread().getName();}private static void log(String log) {Log.d("FlatMap", log);}

这是运行结果:

D/TransformingOperations: 开始执行,第1圆球的任务  |  ThreadName=main
D/TransformingOperations: 开始执行,第2圆球的任务  |  ThreadName=main
D/TransformingOperations: 开始执行,第3圆球的任务  |  ThreadName=main
D/TransformingOperations: 已完成第2圆球的第1个棱形任务  |  ThreadName=RxNewThreadScheduler-2
D/TransformingOperations: 已完成第3圆球的第1个棱形任务  |  ThreadName=RxNewThreadScheduler-3
D/TransformingOperations: 已完成第1圆球的第1个棱形任务  |  ThreadName=RxNewThreadScheduler-3
D/TransformingOperations: 已完成第1圆球的第2个棱形任务  |  ThreadName=RxNewThreadScheduler-3
D/TransformingOperations: 已完成第2圆球的第2个棱形任务  |  ThreadName=RxNewThreadScheduler-2
D/TransformingOperations: 已完成第3圆球的第2个棱形任务  |  ThreadName=RxNewThreadScheduler-2

从打印的结果可以看到,FlatMap,首先是从1到3,即从左到右,执行任务的。其中,1、2、3又各自包含2个子任务。虽然是从1到3开始执行。但是,很明显,未必就是1先执行完毕。反而是,2、3的第一个任务先完成,然后,才是1的两个任务完成。然后,才是2、3的两个被延时处理的任务被分别完成。从这个例子,我们得出这样一个结论:FlatMap执行流程是:先将所有一级任务,铺平成所有二级任务。再依照,从左到右到执行次序,执行任务。但是,任务成功的回调,却不是从左到右的。而是,谁先完成谁先回调。简言之,即:执行次序是一定的,完成次序是不确定的。

四、让我们来看看Rx官方是怎么解释的

FlatMap,英文水平有限,如果翻译有不当之处,欢迎各种建议。

1、transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable。

翻译过来就是:由一个Observable发射一组任务,来将它们转成多个Observable。然后,铺平那些Observable到一个Observable里面。听起来是不是很难理解?因为这是硬翻译,来看看软翻译怎么说:

由一个Observable来触发执行,一组转换任务。做法是:先将这些任务以及它们的子任务,提出来。然后,再将这些任务合并到一个Observable里面。最后,由这个Observable,对这些任务进行遍历处理。。。如果还看不懂,没关系,下面还有更详细的解释。

2、The FlatMap operator transforms an Observable by applying a function that you specify to each item emitted by the source Observable, where that function returns an Observable that itself emits items. FlatMap then merges the emissions of these resulting Observables, emitting these merged results as its own sequence.

This method is useful, for example, when you have an Observable that emits a series of items that themselves have Observable members or are in other ways transformable into Observables, so that you can create a new Observable that emits the complete collection of items emitted by the sub-Observables of these items.

Note that FlatMap merges the emissions of these Observables, so that they may interleave.

In several of the language-specific implementations there is also an operator that does not interleave the emissions from the transformed Observables, but instead emits these emissions in strict order, often called ConcatMap or something similar.

FlatMap操作符,转换一个Observable的做法是,对每一个任务,都通过调用SourceObservable的方法来实现转换。这个方法由你实现,具体的转换逻辑,就在这个方法里面处理。并且,该方法会返回一个Observable,这个Observable又可以处理它自己的任务。FlatMap会合并所有的任务,即将一级任务,先全部转成二级任务,再遍历处理。

这个方法是很有用的。比如说,当你的Observable执行一组任务,或处理一组数据的同时。这些任务或数据,又包含有自己的任务,或数据。所以,你可以为每一个任务,创建一个Observable来处理,它们的二级任务。

注意:因为FlatMap会合并所有的任务。所以,它们可能会有交叉现象。。这句话的意思是,因为将所有一级任务的二级任务都合并成一条线。然后,遍历执行。这样,有的任务,可能会因耗时而慢回调。从而导致,先执行,后回调的现象。

最后一段,简而言之:如果,你既想实现这个功能,又不想出现交叉。即每一个任务,都会等前一个任务,执行完,再回调。可以用ConcatMap操作符。下篇,我们会讲:ConcatMap操作符和FlatMapIterable操作符。


到此为止,FlatMap操作符的讲解,已经全部说完了。如果,你还有什么疑惑不解,可以在评论区指出。

附上可以跑的代码(0 warnings, 0 errors):
https://github.com/SuperBeagleDog/OkMVP

注意:
这个库里面有很多东西,RxJava2的转换操作符部分的demo位于:com.lyf.okmvp.demo.rxjava2包下的TransformingOperations类里面。

用法:
1、直接在com.lyf.okmvp.ui包下的MainActivity类里的onCreate()方法里面,直接调用:

TransformingOperations.actionFlatMap(); // 静态方法。

2、也可以复制TransformingOperations类到你的项目里,去为所欲为。但前提时,你得有配置过RxJava和RxAndroid。配置方法,自行百度,或参考我的OkMVP库。

RxJava2 转换操作符之FlatMap()方法相关推荐

  1. 【C++ 语言】类型转换 ( 转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast | 字符串转换 )

    文章目录 I . const_cast 转换操作符 II . static_cast 转换操作符 III . dynamic_cast 转换操作符 IV . reinterpret_cast 转换操作 ...

  2. python utf-8编码转换中文_python实现unicode转中文及转换默认编码的方法

    本文实例讲述了python实现unicode转中文及转换默认编码的方法.分享给大家供大家参考,具体如下: 一.在爬虫抓取网页信息时常需要将类似"\u4eba\u751f\u82e6\u77e ...

  3. java flatmap_Java 8 Steam API map和flatMap方法使用详解

    java 8 stream api 中有两个方法map和flatMap非常实用,应用场景也非常广泛,能极大提升编程效率.下面我们详细介绍一下这两个方法的用法. map方法 我们来看个示例:把一个整数列 ...

  4. python文件编码转换工具_python实现unicode转中文及转换默认编码的方法

    本文实例讲述了python实现unicode转中文及转换默认编码的方法.分享给大家供大家参考,具体如下: 一.在爬虫抓取网页信息时常需要将类似"\u4eba\u751f\u82e6\u77e ...

  5. C#中如何利用操作符重载和转换操作符

    操作符重载 有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成 ...

  6. python unicode码转换_python实现unicode转中文及转换默认编码的方法

    本文实例讲述了python实现unicode转中文及转换默认编码的方法.分享给大家供大家参考,具体如下: 一.在爬虫抓取网页信息时常需要将类似"\u4eba\u751f\u82e6\u77e ...

  7. python unicode编码转换中文_python实现unicode转中文及转换默认编码的方法

    本文实例讲述了python实现unicode转中文及转换默认编码的方法.分享给大家供大家参考,具体如下: 一.在爬虫抓取网页信息时常需要将类似"\u4eba\u751f\u82e6\u77e ...

  8. java steam说明_Java 8 Steam API map和flatMap方法使用详解

    一对多的提取内容用flatmap,一对一用map java 8 stream api 中有两个方法map和flatMap非常实用,应用场景也非常广泛,能极大提升编程效率.下面我们详细介绍一下这两个方法 ...

  9. python 中文转unicode编码_python实现unicode转中文及转换默认编码的方法

    本文实例讲述了python实现unicode转中文及转换默认编码的方法.分享给大家供大家参考,具体如下: 一.在爬虫抓取网页信息时常需要将类似"\u4eba\u751f\u82e6\u77e ...

最新文章

  1. Google AI 教育项目今起免费开放,支持中文
  2. Scrapy-redis实现分布式爬取的过程与原理
  3. (11)python里面while到底有多少知识点
  4. cygwin的安装使用
  5. 《Android Design》 4.4 中文版
  6. SpringCloud--GateWay搭建及路由转发规则介绍
  7. python 并发编程 多线程 守护线程
  8. 服务器 --- 开发框架
  9. Spark 中 map 与 flatMap 的区别
  10. 【车标识别】基于SIFT算子的车标识别算法matlab仿真
  11. 基于微信旅游景区购票小程序毕业设计毕设作品(5)开题报告答辩PPT
  12. 一文彻底搞懂 顶背离 底背离 (图解)
  13. R语言使用rbind函数向量或者dataframe数据和另外一个dataframe数据纵向合并起来(vertically)
  14. 揭秘全美第一黑客组织Anonymous(匿名者)的装备库
  15. mysql1055_MySQL5.7 group by新特性报错1055的解决办法
  16. Unity游戏动画 从入门到住院 4:动画状态机
  17. Unable to process Jar entry [org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration
  18. 连接redis服务器提示:Redis Client On Error Error connect ECONNREFUSED 127.0.0.16380 Config right
  19. 搜狗输入法的使用感受与评价
  20. 正确思维,和非理性自我斗争

热门文章

  1. 目标检测FPN(Feature Pyramid Networks)的使用
  2. 搭建PC网校的4大优势
  3. 车牌号校验规则,包括新能源车
  4. 学习笔记DL003:神经网络第二、三次浪潮,数据量、模型规模,精度、复杂度,对现实世界冲击
  5. java edt,java – 如何在Swing中分析EDT?
  6. 计网PPT 第九章 无线网络和移动网络
  7. OA电子表单设计-年假申请单-数据验证
  8. 机器学习—多元线性回归案例
  9. 运动场球具的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  10. 夏普电视能用鸿蒙吗,夏普电视怎么安装第三方软件,看电视直播教程