Android kotlin 流在可见时收集初始值



我正在尝试不同类型的流,例如具有通道的流,共享流和状态流。我所做的是,假设我有一个MainActivity,里面有两个并排的按钮在顶部,在它们下面有一个fragmentContainerView。最初,fragmentContainerView没有任何片段。

现在我有一个 viewModel,我在一个循环中发出一系列 int 值,所有三种流类型都有 1 或 2 秒的延迟。我有 MainActivity、片段 A 和片段 B 中值的使用者(片段 B 在收集时在所有三个流中都有 collectLate)。单击按钮 1 附加片段 A,单击按钮 2 附加片段 B。

现在,从 0 开始发出值后会发生什么。一旦发出值,主活动就会开始接收。然后,当我单击按钮 1 时,片段 A 开始从初始值 0 接收。一段时间后,我单击按钮 2 删除片段 A 并附加片段 B,现在片段 B 开始从具有 collectLatest 的值 0 开始后退。同样,如果我单击按钮 1,片段 A 从初始值 0 开始接收。

我可以理解,当片段不可见时,它们不应该收到任何值。但我想了解这是预期的行为,例如每当一个新片段可见时,它就会从初始值接收,而不是让 collectLatest 不起作用。我做错了什么还是为什么会这样?以前的初始值是否存储在某种形式的缓存中?如果我在某个地方想在视图可见时获取当前的最新值,我该怎么做?一些示例代码的指导将有所帮助。谢谢

修复了问题:

实际上,我犯了一个错误,即在片段中创建视图模型的新实例,并且是 viewModel 发出值的地方。通过获取 MainActivity 的视图模型实例在任何地方来修复它。

听起来您使用的是冷流而不是热流。

冷流的行为是,每个新的收集器从一开始就获取值(流生产者为每个收集器启动一个新的生产过程)。例如,如果您使用flow流构建器,如下所示:

val flow = flow {
for (i in 1..3) {
emit(i)
delay(100)
}
}

然后,每次协程调用collect时,该协程都将从上述 lambda 函数的开头开始获得一个新的值流。

对于热流,行为取决于实现。基于通道的流呈扇出,这意味着没有两个收集器将永远接收相同的值。对于发出的每个值,只有一个收集器将接收它。共享流可以有一个缓冲区,该缓冲区为每个收集器重播最多一定数量的过去值。StateFlow 的行为类似于重播值为 1 的 SharedFlow。每个新收集器只能收集最新值,后跟任何进一步的最新值,如果收集速度慢于生成的值,它将跳过值。

通常推荐在适合大多数用途的 ViewModel 中使用的流类型是重播缓冲区为 1 的 SharedFlow,如果基于使用shareIn的上游流,则 SharingStarted 为WhileSubscribed(5000)。这是一个热流,但新订阅者从重播中获得最近发出的值。因此,如果屏幕旋转,最新的值仍在内存中,可以立即显示在 UI 中。当屏幕上不再有从上游流收集的视图时,SharingStarted.WhileSubscribed(5000)允许它停止从上游流收集,但 5 秒缓冲区会等待以确保它不仅仅是屏幕旋转导致非常暂时的订阅者不足。

相关内容

  • 没有找到相关文章

最新更新