我尝试使用stateIn
将几个SharedFlow
组合成一个StateFlow
。但我的StateFlow
似乎没有更新后,我发出新的价值,它的SharedFlow
源。我发现问题出在我如何使用stateIn
。
这是我使用的简化代码(你可以从kotlin playground运行它)。
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
fun main() = runBlocking {
val sourceFlow = MutableSharedFlow<Int>()
val stateFlow = sourceFlow.stateIn(GlobalScope, SharingStarted.Lazily, 0)
val job = launch { stateFlow.collect() }
sourceFlow.emit(99)
println(stateFlow.value)
job.cancel()
}
println(stateFlow.value)
在应该打印99
时打印出0
。我已经完成了关于stateIn的文档,但仍然找不到问题。有人知道我哪里做错了吗?
简短的回答是,当发出99时没有开始收集,因此该值被简单地丢弃。这是SharedFlow
文档中描述的无缓冲共享流的预期行为:
使用MutableSharedFlow()构造函数创建的共享流的默认实现,没有参数,没有重播缓存,也没有额外的缓冲区。对这种共享流的emit调用将挂起,直到所有订阅者接收到发出的值,如果没有订阅者,则立即返回。.
sourceFlow
(共享流)上没有订阅者的原因是您在此流上使用SharingStarted.Lazily
调用stateIn()
:
共享在第一个订阅者出现时开始并且永不停止
这意味着只有当第一个订阅者开始收集状态流时,状态流的协程才开始收集源。在状态流上没有订阅者的原因是,在到达emit之前,您的launch还没有时间调用collect
。
当你调用launch
时,你正在启动一个异步操作。launch
内部的代码与后面的代码并发运行。由于您在runBlocking
的作用域中运行这个launch
,这意味着它与main
的其他代码在同一个线程上运行,这意味着launch
的主体在主函数的主体实际挂起之前无法开始运行。在这里,它只在到达emit()
时暂停。