RxJava进阶之源码分析(part 3)- observeOn() 操作符分析

隔了好久,终于有时间更新一下RxJava进阶的最后一篇文章了。前几个星期有幸参加了今年的Google I/O(谷歌举办的一年一度的开发者大会,今年在谷歌总部举行),去了一趟迷人的加州,于是文章被拖延了。有兴趣的朋友可以看看我上一篇类似于日志的google之行文章。

五月,Google I/O 之行

上一次我们介绍了subscribeOn操作符的源码,那么这一次回到正题,把observeOn操作符的用法和源码过一遍。

我们先看看这个例子:

转换很简单,我们先发射1,2,3这三个数字,在IO线程进行第一次转换,在computation线程进行第二次转换,最后在newThread线程进行打印。我们来观察一下打印结果。大家可以根据自己对observeOn操作符的理解先预测一下。(注意我在发射元素的地方进行了sleep操作,暂停当前线程一秒钟,原因之后会解释)

按照我们之前对map操作符的理解,这组操作应该会是把对数字1先后进行转换1,转换2,打印,然后在对2做同样的操作。

那么我们来看看结果是否是这样?

终于预测正确了一次

哈哈,终于,我们这次预测对了。的确是按照我们事前所想的那样把三个数字分别打印出来的。observeOn操作符的作用也正是如此,每次使用observeOn,都会把这个observeOn下面的操作包装在该observeOn指定的线程池中运行。

还记得上一篇讲过的subscribeOn操作符嘛,subscribeOn只能作用一次,而observeOn可以作用多次。原因我们接下来也会讲。

那么我们跟踪源码,由于我们之前几篇已经讲过RxJava的lift方法和大概的工作原理,这篇我就不多说lift的具体作用,假设大家已经了解相关知识了,如果不了解的请从map的源码分析开始。

observeOn操作符会用OperatorObserveOn改变原有的Subscriber(大家应该还记得原有的subscriber是从哪来的吧?没错这里说的原有的subscriber就是从下一级传上来的subscriber)。

OperatorObserveOn

在这个操作符的call方法里面(大家还记得lift方法会用操作符的call方法改变原有subscriber对吧?),生成新的Susbcriber,ObserveOnSubscriber

新的Subscriber里面,结构有点点复杂,有一个队列,然后把原有的subscriber的引用传进来,作为自己的成员对象。

新的subscriber

新的subscriber里面,我们重点关注onNext()方法做了些啥,因为每次发射元素,都是先调用新的subscriber的onNext()方法的。

新的onNext方法会先把我们发射的原始元素添加到队列里面(line129),如果发生错误,执行onError,并且返回(line 130 - 131)。假如添加元素成功,执行schedule()。

在创建了一个新的Action对象之后,我们把对象放入一个Scheduler里面执行了。如果大家还记得上一篇文章的内容,应该了解这个Action和Scheduler的关系。类似于Java里面Runnable对象和ExecutorService一样,最后Action里面的操作会被放入线程池,寻找合适的线程执行。

所以其实最后兜兜转转,最重要的,需要执行的方法就是这个pollQueue(),这个方法从名字就可以看得出来是要获取队列元素了。而事实也的确如此,我们看看pollQueue方法里面最重要的部分。


pollQueue方法使用了一个死循环(line 182),不断的去查看queue里面的元素。我们这里重点关注line 200 -202, 在把队列里面的第一个元素取出之后,我们交给child,也就是包装进来的,来自下一级的subscriber,让它来执行它的onNext()。这样,我们的原始的Observable的第一个元素就这样处理完毕了。

这整一个pollQueue方法,因为被包装在Action对象里面,而Action对象又会被放进Scheduler,也就是RxJava包装过之后的ExecutorService里面执行,所以它是会运行在我们指定的那个线程里面的。我们可以在debug模式下面验证一下。

currentThread已经不是安卓的主线程了

所以总结一下的话,使用observeOn,会在原有的Observable发射元素的时候,将元素依次添加到一个队列中,并异步的(使用一个新的线程去执行)不停的去获取队列的第一个元素,使用下一级的subscriber处理(onNext())该元素。

简单的结构图


大家可以这样理解每次发射新元素的时候。。。

那么我们再将思维拓展一下,如果在observeOn后面跟的不是subscribe()方法,而是一个map方法。会有什么不同呢?

如果是map的话,大家应该还记得,下一级传上来的subscriber也不会是我们在subscribe()方法里面传进来的subscriber,而是经过OperatorMap改造过的subscriber了。

OperatorMap的onNext()方法

也就是说,pollQueue方法的line202,child成员就是OperatorMap改造后的subscriber,那么执行的onNext()也就是上图line52-58的这个onNext方法了,line 54中,我们会在observeOn操作符里面的定义的线程中,执行transformer.call(t),也就是说,我们保证了map操作符里面的call()方法(就是我们进行类型转换的方法)是执行在observeOn所定义的线程中,然后在执行o.onNext(),这个o对象,又是下一级传上来的subscriber。

所以,假如我们遇到了多次的ObserveOn+Map的转换的话,发射元素的流程就变成这样了:

三层observeOn+map的转换

回到我们开头的问题,为什么我们要在原始的Observable发射元素之间,暂停当前线程一秒?

理由很简单,因为如果不这样做的话,我们的map转换会被放到ExectuorService里面执行,是异步执行的,所以很有可能会出现;第一层转换都执行完毕,才执行下一层转换,最后日志的打印结果就不是我们预测的那样了。

大家想象一下,把上图的第二和第三层向右方无限拉长,拉倒第三map之后,就会出现RxJava似乎是在处理完一层之后再处理下一层的错觉。


那么到此为止,RxJava进阶的所有专题都结束了,其实关于RxJava,还有很多东西我们都没接触,例如怎么handle Subscription等等。这也就留给有兴趣的同学自己慢慢摸索了。接下来我会专心准备Android Tv的教程给大家。希望有兴趣开发安卓TV应用的同学们留意一下 ;)


另外,很高兴勇士赢球,作为一个库里球迷,我忍不住上个图:


let's go warriors
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容