Kotlin之flow执行顺序分析(一看就会系列)

前言
PS:以下flow都是基于kotlin

flow对于初学者来说大部分都是处于只会用的阶段。但是flow到底是如何通过emit发送消息给collect接收的呢?估计还是云里雾里的(好吧,那个初学者就是我!)
大部分博客介绍flow都是对比RxJava来讲解。但是对于没使用过RxJava的人来说看着同样是迷迷糊糊。(我承认,这说的也是我😂)

先看一小段测试用例

测试代码.png

输出日志.png

通过测试用例可以明显的看出是先执行了flow代码块再执行的collect代码块。

疑问:
  • 那么它是什么时候执行flow的代码块呢?
  • 又是什么时候执行collect的代码块呢?
  • emit方法调用又是如何执行到collect里的呢?
  • 它们之前是如何交互的?
  • 又存在什么关系呢?

在我们平常开发中,两个类交互大多数情况下都是使用接口的方式。在flow中使用的同样也是接口的方式。而flowcollect这两个方法交互方式正是由interface Flow<out T>interface FlowCollector<in T>这两个接口来衔接的

交互桥梁
FlowCollector.png
Flow.png

既然我们已经知道了它们通信的工具是接口,那我们具体来看看它们内部是如何运作的吧。

flow()源码分析

flow.png

首先我们可以看到flow()里面需要传入了一个FlowCollector的扩展方法。同时会返回一个Flow接口类型实例,而调用flow的时候实际执行的是创建一个SafeFlow类。SafeFlow类也很简单,它就继承了AbstractFlow类,并且实现了collectSafely抽象方法。从目前来看,当触发collectSafely方法时,就会回调到我们外部flow中的方法体里。也就是我们传进来的FlowCollector的扩展方法。

  • 到这一步不知道大伙会不会有新的疑惑?比如说“为啥需要传FlowCollector的扩展方法,直接传一个普通方法不就可以实现方法的回调吗?”说到这里,不得不夸夸kotlin了,方法参数支持函数(方法)传值,属实好用,它方法里面可以传递方法,可以帮我们省去不少接口的创建。那这里为什么不直接传普通方法呢?

其实这个问题很好解释,考虑到需要与collect方法通信,如果只传普通的方法,那只能做到单向通信了。collect直能发送信息,无法接收信息。而传接口类型的扩展方法就可以做到双向通信了。

我们接着看看什么时候会去触发collectSafely这个方法。我们去SafeFlow类的父类看看。

AbstractFlow.png

AbstractFlow类也是很简单的。我们可以看到在collect方法执行的时候就会触发我们上面说的collectSafely方法,说了这么多,那最终是谁调用了collect呢?这里就应用到了第一个接口Flow,因为collect方法是Flow接口内的方法,flow方法又会返回一个Flow的实例,所以flow返回的实例调用collect这个方法时就会执行flow中的代码块。

接着我们在看看collect方法里面做了什么。

collect()源码分析

collect.png

可以看到,这个方法需要Flow类型才可以调用。正好我们flow方法会返回一个Flow类型实例。而调用collect方法实际就是调用了调用者的collect方法,并且传入了一个collector: FlowCollector<T>接口的匿名对象实例,这个匿名对象还重写了它的emit方法。如果说将此匿名对象传给类flow方法中,就可以很好的理解了为什么在flow的方法体中调用emit可以回调到collect方法中了。

既然说了如果,就是肯定没有直接传过去咯。相信细心的小伙伴其实早就发现了吧。在collect方法中还创建了一个SafeCollector类,并且把它传入到collectSafely方法中了。(PS:单从它的名字可以看出,它是一个安全的数据接收者,内部如何做的安全处理我下面没细说,如果需要了解的小伙伴可以查看我最后的参考文献)并没有直接将我们的匿名对象传递过去。那我们就看看SafeCollector类里面又做了什么吧。

SafeCollector.png

SafeCollector类其实也是继承了FlowCollector<T>接口的,所以传递给flow方面里面可以调用emit方法,也就执行了SafeCollector类中的emit方法。
emit.png

而它要想回调到collect方法中去,它必然需要通过我们传进来的匿名对象去实现,所以我们只需要关注emitFun(collector as FlowCollector<Any?>, value, this as Continuation<Unit>)这个方法,因为flow中调用emit方法最终也是会执行到这一步的。单纯的看private val emitFun = FlowCollector<Any?>::emit as Function3<FlowCollector<Any?>, Any?, Continuation<Unit>, Any?>这段代码就是把FlowCollector<Any?>::emit转换成三参数的方法调用,可能不是太好理解。我们把它编译成java的代码来看就比较清晰了。

SafeCollector类java代码1.png

可以看到,当调用emit时,它会先调用他双参的方法,在由双参方法里面构建了一个三参数的方法,并invoke了自己三参的方法,在三参方法的第一个参数,将我们的匿名对象传了进去。

SafeCollector类java代码2.png

在使用我们传入的匿名对象调用了两参的emit方法。那又有同学会问了。我们kotlin是单参的emit方法啊,双参数是怎么掉到单参的呢?

FlowCollector类java代码.png

其实我们kotlinemit方法编译成java代码就是双参的。这下应该就都清楚了吧。

总结

1、flow{}中的代码块必须由collect调用后才会执行
2、collect中的代码块由flow{}emit方法调用回调执行

参考文献:Kotlin中flow发射与接收分析
参考文献:协程三部曲之③:Flow 的使用!

上一篇:Retrofit2 的baseUrl 到底要不要以“/”结尾

下一篇:Kotlin之flow执行顺序分析(一看就会系列)

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

推荐阅读更多精彩内容