我们接着上文回忆一下:
flow方法构建的是一个扩展函数
collect作用是创建这个对象调用这个扩展函数。当调用emit方法时执行collect传进来的方法。
操作符
map:flow构建了一个FlowCollector的扩展函数并返回了一个SafeCollector对象。
map方法中会将这个flow进行包装:
public inline fun <T, R> Flow<T>.map(crossinline transform: suspend (value: T) -> R): Flow<R> = transform { //一,对传入的value value -> return@transform emit(transform(value)) }
最终调用transform方法,传入方法实现为调用emittransform后的值。
public inline fun <T, R> Flow<T>.transform( @BuilderInference crossinline transform: suspend FlowCollector<R>.(value: T) -> Unit ): Flow<R> = flow { // Note: safe flow is used here, because collector is exposed to transform on each operation //二,Flow<T>中的flow代码块将被执行,当调用到emit时会走到collect代码块中 collect { value -> // kludge, without it Unit will be returned and TCE won't kick in, KT-28938 return@collect transform(value) } }
此时这个Flow为flow创建的那个SfaceFllow对象。
transform函数会再次构建一个flow再次创建一个SafeFlow对象并保存flow中的方法参数中。
当经过map之后构建的flow调用collect方法时,流程如下:
1.首先会执行transform后的flow代码块,可以看到执行到了collect方法调用者为Flow,也就是上一次调用map的flow对象中的代码块会执行
2.当调用map的flow代码块中调用emit方法会走到transform的collect中,可以看到将value传入到了transform中,此时的调用者为最外层的flow,也因此在调用再看下transform函数,该函数即为map的转换逻辑,接着会自动emit这个转换后的值也就到了第三部
3.调用emit最外层的collect将会被接收到也就是调用map的collect函数将会收到回调,此时收到的值是map转换后的值
TIPS:
流收集时会调用上一个流获取:flow中调用其他flow的collect触发收集,其他flow中提供原始数据,内层收集器进行原始数据封装再提供到最外层收集器中。
收集行为:flow代码块
收集器行为:collect代码块
最后放出这张图片:
总结
以上为个人理解,如有不对辛苦指正。
第一次看到flow感觉好别扭估计是函数式编程还是没有掌握思想,眼过千遍不如手过一遍,下一篇文章中我们自定义一个Flow收集器,并支持最简单的map操作符~