概述
最近想学习一下 Kotlin 中 flow 的用法, Google 上搜了搜发现很多比较 RxJava 和 flow 的文章,其实我在实际业务中从来没有用过 RxJava, 倒不是因为它不好,而是…我一直傻傻不太会用 RxJava 的操作符,看不太懂,又一直没花时间(懒惰)去研究它那些操作符的原理,就一直不怎么敢用。这次看到了 flow, 想着还是先去了解了解它内部几个操作符的原理吧,不然用起来总是不太踏实。
需要注意的是 Flow 需要在协程中使用, 因此配合协程,可以方便地切线程。分析 flow 工作流程离不开协程的工作原理,关于 Kotlin 协程的解析可以参考下列文章:
首先看一下 Flow 接口的源码,内部只有一个 collect 方法:
public interface Flow<out T> {
// 是一个 suspend 方法,意味着会挂起当前协程
@InternalCoroutinesApi
public suspend fun collect(collector: FlowCollector<T>)
}
public interface FlowCollector<in T> {
// 数据的发射方
public suspend fun emit(value: T)
}
flow {}
以下面代码为例,讲解 flow 工作的基本流程:
flow { emit(1) }.collect { println(it) }
首先看一下 flow {}
的源码:
public fun <T> flow(@BuilderInference block: suspend FlowCollector<T>.() -> Unit): Flow<T> = SafeFlow(block)
上面就是以 block 代码块为参数创建了一个 SafeFlow 对象,SafeFlow 实现了 Flow 接口,于是接着看其 collect 方法。
collect
除了一开始贴的实现 Flow 接口调用 collect 方法的方式, Kotlin 还提供了调用 collect 的两个扩展函数,最后都是调用的 fun collect(collector: FlowCollector<T>)
方法:
public suspend fun Flow<*>.collect(): Unit = collect(NopCollector)
public suspend inline fun <T> Flow<T>.collect(crossinline action: suspend (value: T) -> Unit): Unit =
collect(object : FlowCollector<T> {
override suspend fun emit(value: T) = action(value)
})
于是我们接着上面的示例,看一下 SafeFlow.collect 方法:
private class SafeFlow<T>(private val block: suspend FlowCollector<T>.() -> Unit) : AbstractFlow<T>() {
override suspend fun collectSafely(collector: FlowCollector<T>) {
collector.block()
}
}
// collect 方法在父类 AbstractFlow 中
public abstract class AbstractFlow<T> : Flow<T>, CancellableFlow<T> {
public final override suspend fun collect(collector: FlowCollector<T>) {
val safeCollector = SafeCollector(collector, coroutineContext)
try {
collectSafely(safeCollector)
} finally {
safeCollector.releaseIntercepted()