这里记录一些个人关于Flow的简单理解
流分冷热。主要区别与是否需要消费者来使其流动。
没有消费者的冷流是不会传递数据的。是一条冰河。需要消费者来解冻。
热流则无论是否存在消费者,只要有生产者投入数据,则会传递。是始终流动的运河。
思考
初时了解了冷热流的概念,在使用的角度上可以很快的找到两种流对应的场景。但在冷热流交替使用时,总会有一种不同步的冲突感。稍一思量就产生了一个问题。冷流是可以转成热流的,冷流是需要接收者才能流动的。那么这个转换就像是把冰河汇流到一条运河上。冰河是如何解冻的呢?
public fun <T> Flow<T>.shareIn(
scope: CoroutineScope,
started: SharingStarted,
replay: Int = 0
): SharedFlow<T> {
val config = configureSharing(replay)
val shared = MutableSharedFlow<T>(
replay = replay,
extraBufferCapacity = config.extraBufferCapacity,
onBufferOverflow = config.onBufferOverflow
)
@Suppress("UNCHECKED_CAST")
val job = scope.launchSharing(config.context, config.upstream, shared, started, NO_VALUE as T)
return ReadonlySharedFlow(shared, job)
}
冷流的转换方法中,调用了scope的launchSharing方法。
config.upstream为冷流本身
shared 为转换的热流
private fun <T> CoroutineScope.launchSharing(
context: CoroutineContext,
upstream: Flow<T>,
shared: MutableSharedFlow<T>,
started: SharingStarted,
initialValue: T
): Job {
/*
* Conditional start: in the case when sharing and subscribing happens in the same dispatcher, we want to
* have the following invariants preserved:
* * Delayed sharing strategies have a chance to immediately observe consecutive subscriptions.
* E.g. in the cases like `flow.shareIn(...); flow.take(1)` we want sharing strategy to see the initial subscription
* * Eager sharing does not start immediately, so the subscribers have actual chance to subscribe _prior_ to sharing.
*/
val start = if (started == SharingStarted.Eagerly) CoroutineStart.DEFAULT else CoroutineStart.UNDISPATCHED
return launch(context, start = start) { // the single coroutine to rule the sharing
// Optimize common built-in started strategies
when {
started === SharingStarted.Eagerly -> {
// collect immediately & forever
upstream.collect(shared)
}
started === SharingStarted.Lazily -> {
// start collecting on the first subscriber - wait for it first
shared.subscriptionCount.first { it > 0 }
upstream.collect(shared)
}
else -> {
// other & custom strategies
started.command(shared.subscriptionCount)
.distinctUntilChanged() // only changes in command have effect
.collectLatest { // cancels block on new emission
when (it) {
SharingCommand.START -> upstream.collect(shared) // can be cancelled
SharingCommand.STOP -> { /* just cancel and do nothing else */ }
SharingCommand.STOP_AND_RESET_REPLAY_CACHE -> {
if (initialValue === NO_VALUE) {
shared.resetReplayCache() // regular shared flow -> reset cache
} else {
shared.tryEmit(initialValue) // state flow -> reset to initial value
}
}
}
}
}
}
}
}
这个方法就真相大白了。
首先启动了协程 launch(context, start = start)
然后 upstream.collect(shared) 或者 shared.tryEmit(initialValue)
热流作为冷流的消费者在协程中持续将其数据转入自己的数据流。