核心思想:
RxJava学习和使用最重要的是掌握它的核心思想,它在 github 主页的介绍是:
“a library for composing asynchronous and event-based programs using observable sequences for the Java VM”
我理解是:一个运行在 Java 虚拟机上的可序列观察组合、异步和基于事件的库。所以能推导 Rx 定义为:序列观察组合异步事件。
我们能得到几个关键词:
- 序列:对顺序敏感(事件发送)
- 观察:响应式编程
- 组合:可处理多个事件
- 异步:可调度线程
- 事件:可以理解为起点发送的事件,也可以理解为每个中间环节的操作
根据使用经验来总结其核心思想:在起点注册观察后分发一个事件,流式操作中间步骤,终点消费事件解除观察。
因为它的操作符很多,遍历学习操作符性价比很小,我们根据其核心思想,以输出的方式来学习 RxJava。
普通应用:
业务要求1:有一个图片url地址,下载图片并且将图片显示在 ImageView。
思路:事件为下载并且展示图片到 ImageView,事件起点为分发(放置)一个 url 给下游中间步骤1(传送带),下游中间步骤1拿到的为String而步骤二设置图片显示需要的数据为 Bitmap,所以此步骤需要 Map 操作符来将url转换为 Bitmap并且应该 为异步操作,然后将 Bitmap分发给下游中间步骤 2,步骤 2 将 Bitmap更新到 ImageView,消费掉事件,事件结束。
流程图为:
上代码:
|
|
实现完上边需求,产品小姐姐说需要一个加水印的功能,没问题,我们就在上边代码基础上来做改造。
思路:在上述步骤1,拿到 Bitmap 后然后我们将步骤2 改为为 Bitmap 添加水印,然后步骤3 来完成图片的展示和事件的消费。
修改后的流程图为:
上代码:
|
|
防抖:
防抖的意思就是说规定时间内接收到多次事件只触发一次。放置恶意轰炸,或者重复触发问题。
业务需求:如下图,两秒内项目按钮点击只完成一次获取所有项目分类,并且根据项目 id 获取所有项目下的所有列表数据。
一般思路:利用 RxBinding 处理防抖动,然后步骤1,网络获取所有项目数据,数据类型为[ProjectBean,ProjectBean,ProjectBean,ProjectBean,ProjectBean…],步骤 2,根据步骤 1 获取的ProjectBeanList 遍历,分别根据每个 ProjectBean id 去获取项目列表数据。步骤 3,分别获取每个项目的列表数据 [ProjectItem,ProjectItem,ProjectItem,ProjectItem,ProjectItem..]去更新 UI消费掉该事件。
流程图如下:
上代码:(此处为伪代码实现)
|
|
网络嵌套:
上边防抖代码可读性很差,why?因为上边代码有两次嵌套缩进,第一次为实现防抖动,回调缩进了一次,项目列表数据获取也在主数据获取的回调嵌套中。
解决迷之嵌套问题,我们需要了解 RxJava 的另一个操作符:
flatmap:可以将一个观察集合数据的观察者展开为多个观察一条数据的观察者。这也是他和 map 的最主要区别,当集合中只有一条数据时,它的作用将和 map 一样。回顾上边普通应用的需求实现都是从头到尾一个观察者,观察着一条数据向下游流动。
改造版代码:(同样为伪代码)
|
|
连续操作:
上边需求发现没?有一个共同规律,就是都是一个事件开始,然后事件结束。如果实现一个时间开始,一个时间结束,然后再次开启一个事件,然后再次结束第二个事件怎么办?是和上述代码并列,再次创建一个观察者?NO!看下边操作符。
doNoNext:可以用于,多个连续事件,执行过程中,事件都需要按顺序消费掉前边事件然后继续执行后边事件。
业务需求:用户注册完成后更新UI 跳转登录页面并且自动登录后跳转首页。
实现思路:用户点击 reigstBtn获取注册结果,拿到注册结果 UI 线程去跳转登录页面,然后工作线程去根据 reigstResponse 去请求登录数据,拿到登录信息去跳转首页,消费掉这个事件。注意:此时消费掉的事件并非最初事件。
业务流程比较简单,直接代码实现:(伪代码)
|
|
并行操作:
再有一个例子,右下边需求:
|
|
递归:
还是一个需求来看,扫描某个路径下的所有文件,找出格式为 .doc 的文件并输出路径。
直接看代码:
|
|
哈哈哈,咋样,如果你真拿上边代码去应用,就会发现一个问题,卡的一笔。
为什么呢,flatmap 就会创建 n 个 Observable,然后外层递归更可怕 n 的 n 次方个Observable,所以递归中最好都不要有对象的创建,哈哈哈。
看一下下边代码:
|
|
小结
带着本文第一节对“核心思想”的理解,来思考一下这几个业务实现。发现每个业务都重点关注事件的开始和结束也就是事件的传入数据类型和最终消费事件需要的数据类型,中间步骤的所有转换都有操作符去支持我们。
上边图片下载问题可以举个相似栗子:小明肚子饿了,想吃东西利用核心思想来实现一下:
此事件完整实现需要先确定事件开始(大脑饿了信号类型),和事件结束(食物类型)中间具体需要步骤都可以有操作符来实现。
网络嵌套需求举个相似栗子:小明饿了,想吃 10 种东西:
连续操作需求举一个相似栗子:小明饿了,吃完饭然后去上学。
关注开始与结束