flowOn
学习 flow 一个绕不开的操作符就是 flowOn 了,以下面示例代码为例, flow 需要在协程中使用,下面的 emit(1)
会在 Dispatchers.Default 指定的线程中执行,而 println(it)
会在父协程所在线程中执行:
flow { emit(1) }.flowOn(Dispatchers.Default).collect { println(it) }
flow {}
的源码在上面已经看过了,就是以 block 代码块为参数创建了一个 SafeFlow 对象,接下来看一下 Flow.flowOn 的逻辑:
public fun <T> Flow<T>.flowOn(context: CoroutineContext): Flow<T> {
checkFlowContext(context)
return when {
// 返回自身 Flow 实例
// 这里我们传入了 Dispatchers.Default, 所以不符合这个条件
context == EmptyCoroutineContext -> this
// SafeFlow 不是该类型,因此也不走这个流程,实际上 FusibleFlow 是当连续多次调用 flowOn 后会创建的 Flow 对象
this is FusibleFlow -> fuse(context = context)
// 逻辑走到这里
else -> ChannelFlowOperatorImpl(this, context = context)
}
}
在上面已经对流程注释了一下,因此上述实例代码转换一下即为: SafeFlow.flowOn.collect {} --> ChannelFlowOperatorImpl.collect {}
, 这里注意一下创建 ChannelFlowOperatorImpl 对象时传入的两个参数,第一个 this 指的是之前的 SafeFlow 对象,第二个 context 参数即是我们传入的调度器,它是一个协程上下文。
ChannelFlowOperatorImpl.collect 实现在父类 ChannelFlowOperator.collect 中,该方法如果发现传入的 coroutineContext 上下文中没有携带调度器,即我们调用 flowOn 时没有传入 Dispatchers 等调度器,则会直接调用上一层 SafeFlow 的 collect 方法(代码不贴了),否则接着调用父类 ChannelFlow 中的 collect 方法,我们直接看 flowOn 中传入了调度器后的逻辑:
internal abstract class ChannelFlowOperator<S, T>(
@JvmField protected val flow: Flow<S>,
context: CoroutineContext,
capacity: Int,
onBufferOverflow: BufferOverflow
) : ChannelFlow<T>(context, capacity, onBufferOverflow) {
override suspend fun collect(collector: FlowCollector<T>) {
// 判断 coroutineCon