MutableStateFlow 事件被覆盖
MutableStateFlow events being overwritten
在 MyViewModel 中,MutableStateFlow 用于将事件传输到片段。
当 MutableStateFlow 的值更改时,先前的值将在协程内被覆盖。所以从来没有被片段接收到。
internal class MyViewModel(application: Application) : AndroidViewModel(application) {
private val myMutableStateFlow = MutableStateFlow<MySealedClass>(MySealedClass.Dummy1())
private fun getData() {
viewModelScope.launch {
//yield()
myMutableStateFlow.value = MySealedClass.Dummy2()
myMutableStateFlow.value = MySealedClass.Dummy3()
}
}
}
internal class MyFragment : Fragment(){
private var uiStateJob: Job? = null
override fun onStart() {
super.onStart()
uiStateJob = lifecycleScope.launch {
myViewModel.getUiFlow().collect {
//do something
}
}
}
}
如果对 yield() 进行了注释,则 Fragment 永远不会收到 Dummy2 事件。虽然收到了虚拟 3。
如果 yield() 未被注释,则 Dummy2 和 3 都被接收。
如果状态值在协程之外发生更改,则同时接收 Dummy2 和 Dummy3。
我需要以可预测的方式接收片段中的所有事件。
这种行为有正确的理由吗?
StateFlow
代表一个状态。每个事件在技术上都是一个新的最新状态值,使以前的状态过时。这种类型的流程适用于只有最新状态很重要的情况,因为它的事件是 混淆的 。来自文档:
Updates to the value are always conflated. So a slow collector skips fast updates, but always collects the most recently emitted value.
根据您的评论进行编辑:yield()
是一个暂停函数,强制暂停当前协程。因此,它为另一个协程提供了一个机会,直到它的下一个暂停点,这就是为什么在第一个值设置(并发出)之前收集“准备好”的原因。
但是你不应该依赖它,因为它很脆弱:如果另一个协程被修改并且通过调用其他挂起函数有额外的挂起点,它可能无法到达 collect
调用,你会回到其他行为。
如果您始终需要所有事件,您有多种选择:
- 切换到冷流,只有在您收集时才会启动
- 使用
Channel
(带或不带缓冲区)
- 使用
SharedFlow
并使用 onSubscription
触发事件开始
在 MyViewModel 中,MutableStateFlow 用于将事件传输到片段。 当 MutableStateFlow 的值更改时,先前的值将在协程内被覆盖。所以从来没有被片段接收到。
internal class MyViewModel(application: Application) : AndroidViewModel(application) {
private val myMutableStateFlow = MutableStateFlow<MySealedClass>(MySealedClass.Dummy1())
private fun getData() {
viewModelScope.launch {
//yield()
myMutableStateFlow.value = MySealedClass.Dummy2()
myMutableStateFlow.value = MySealedClass.Dummy3()
}
}
}
internal class MyFragment : Fragment(){
private var uiStateJob: Job? = null
override fun onStart() {
super.onStart()
uiStateJob = lifecycleScope.launch {
myViewModel.getUiFlow().collect {
//do something
}
}
}
}
如果对 yield() 进行了注释,则 Fragment 永远不会收到 Dummy2 事件。虽然收到了虚拟 3。 如果 yield() 未被注释,则 Dummy2 和 3 都被接收。 如果状态值在协程之外发生更改,则同时接收 Dummy2 和 Dummy3。
我需要以可预测的方式接收片段中的所有事件。 这种行为有正确的理由吗?
StateFlow
代表一个状态。每个事件在技术上都是一个新的最新状态值,使以前的状态过时。这种类型的流程适用于只有最新状态很重要的情况,因为它的事件是 混淆的 。来自文档:
Updates to the value are always conflated. So a slow collector skips fast updates, but always collects the most recently emitted value.
根据您的评论进行编辑:yield()
是一个暂停函数,强制暂停当前协程。因此,它为另一个协程提供了一个机会,直到它的下一个暂停点,这就是为什么在第一个值设置(并发出)之前收集“准备好”的原因。
但是你不应该依赖它,因为它很脆弱:如果另一个协程被修改并且通过调用其他挂起函数有额外的挂起点,它可能无法到达 collect
调用,你会回到其他行为。
如果您始终需要所有事件,您有多种选择:
- 切换到冷流,只有在您收集时才会启动
- 使用
Channel
(带或不带缓冲区) - 使用
SharedFlow
并使用onSubscription
触发事件开始