Android 正在覆盖的可变状态流事件

Android 正在覆盖的可变状态流事件,android,kotlin,coroutine,stateflow,Android,Kotlin,Coroutine,Stateflow,在MyViewModel中,使用可变状态流将事件传输到片段。 当MutableStateFlow的值更改时,早期的值将在协同例程中被覆盖。所以从未收到过碎片 internal class MyViewModel(application: Application) : AndroidViewModel(application) { private val myMutableStateFlow = MutableStateFlow<MySealedClass>(MySealedC

在MyViewModel中,使用可变状态流将事件传输到片段。 当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
           }
       }
    }
}
内部类MyViewModel(应用程序:应用程序):AndroidViewModel(应用程序){
private val myMutableStateFlow=MutableStateFlow(MySealedClass.Dummy1())
私有数据{
viewModelScope.launch{
//收益率()
myMutableStateFlow.value=MySealedClass.Dummy2()
myMutableStateFlow.value=MySealedClass.Dummy3()
}
}
}
内部类MyFragment:Fragment(){
私有变量uiStateJob:作业?=null
覆盖有趣的onStart(){
super.onStart()
uiStateJob=lifecycleScope.launch{
myViewModel.getUiFlow().collect{
//做点什么
}
}
}
}
如果对yield()进行了注释,则片段永远不会收到Dummy2事件。但收到了虚拟3。 如果yield()未注释,则会同时收到Dummy2和3。 如果状态值在协同程序外更改,则同时接收Dummy2和Dummy3

我需要可预测地接收片段中的所有事件。
这种行为有正确的理由吗?

StateFlow
表示一种状态。从技术上讲,每个事件都是一个新的最新状态值,使以前的状态过时。这种类型的流适用于只有最新状态才重要的情况,因为它的事件是合并的。从文档中:

对值的更新始终合并。因此,较慢的收集器跳过快速更新,但始终收集最近发出的值

编辑以响应您的评论:
yield()
是一个暂停函数,强制暂停当前协同程序。因此,它给了另一个协程一个机会,让它继续前进,直到下一个暂停点,这就是为什么在这种情况下,在设置(并发出)第一个值之前,collect是“就绪”的

但是,您不应该依赖它,因为它很脆弱:如果另一个协同程序被修改,并且通过调用其他挂起函数具有额外的挂起点,它可能无法到达
collect
调用,您将返回到另一个行为

如果您始终需要所有事件,您有几个选项:

  • 切换到冷流,仅在收集时启动
  • 使用
    频道
    (带或不带缓冲区)
  • 使用
    SharedFlow
    并通过使用订阅上的
    onSubscription来触发事件启动

这是有道理的。但是这种行为不应该是一致的吗?看起来,如果在协同程序中更改状态,那么只会发生合并。如果不在协程内,则接收连续状态而不合并。我也不清楚yield()语句是如何改变这种情况的。它不必以合并事件的方式具有确定性或一致性,因为设计在这方面没有保证。我编辑了我的帖子来解释收益率。