Kotlin协程:Flow的流式调用原理

10,425 阅读2分钟

    本文分析示例代码如下:

flow {
    emit(1)
}.flowOn(Dispatchers.Main).onEach {
    Log.d("liduo", "onCreate1: $it")
}.collect {
    Log.d("liudo", "onCreate2: $it")
}

一.链式调用原理

    在协程Flow中,除了flow方法外的其他方法,都是Flow接口的扩展方法,这些方法也被称作操作符。而flow方法用于创建一个类型为Flow的对象,一般用于创建整条链中的第一个Flow对象。

    在协程Flow中,除了collect方法外的其他方法,在被调用后都会返回一个Flow对象。这里的collect方法不是在Flow接口中定义的方法,而是Flow接口的扩展方法,一个操作符,一般用于在整条链创建完毕后,最为最后一个操作符调用,触发整条链的执行。

    这样,通过扩展方法与返回对象的统一,实现了链式调用。从第一个操作符的调用,到最后一个操作符的调用,形成了一个类似于上下游的流式结构。

    由于后一个操作符是前一个操作符返回的Flow对象的扩展方法,因此后一个操作符会持有前一个Flow对象的引用,因此可以通过调用上一个Flow对象的collect方法,触发上游Flow对象的执行。 image.png     同时,想要调用Flow对象的collect方法,需要向collect方法内传递一个类型为FlowCollector的参数。这样,上游的Flow对象就会持有一个下游的类型为FlowCollector对象的引用。而上游Flow对象的参数block,正是下游FlowCollector对象的扩展方法。

    通过每一级Flow对象的层层触发,最后会调用到最上游Flow对象的collect方法。这时,最上游Flow对象的block参数会执行。当需要向下游Flow对象发送值时,会调用emit方法,由于参数block是下游FlowCollector对象的扩展方法,因此调用的emit方法也是下游FlowCollector对象实现的emit方法。

    这样上游发送的值层层向下传递,在中间过程可能会被变换处理或直接透传,最后传递到最下游的操作符并调用其参数block处理。这里的block由于是最下游操作符的block,因此它不是FlowCollector对象的扩展方法,因此也就不能调用emit方法发送值,只能进行处理操作。