【问题标题】:Android kotlin flows collects initial values when visibleAndroid kotlin 流在可见时收集初始值
【发布时间】:2022-09-22 22:45:04
【问题描述】:

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

现在我有一个 viewModel,我在循环中发出一系列 int 值,所有三种流类型都有 1 或 2 秒的延迟。而且我有 MainActivity、fragmentA 和 fragmentB 中的值的消费者(收集时,fragmentB 在所有三个流中都有 collectLatest)。单击button1 附加fragmentA,而Button2 附加fragmentB。

现在假设最初从 0 开始发出值后会发生什么。一旦发出值,mainActivity 就会开始接收。然后,当我单击 button1 时,fragmentA 开始从初始值 0 接收。一段时间后,我单击 button2 删除 FragmentA 并附加 FragmentB,现在 FragmentB 从具有 collectLatest 的值 0 开始接收。如果我再次单击 button1,fragmentA 从初始值 0 开始接收。

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

    标签: android kotlin kotlin-coroutines android-jetpack


    【解决方案1】:

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

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

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

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

    对于热流,行为取决于实现。基于通道的流呈扇形散开,这意味着没有两个收集器会收到相同的值。对于每个发出的值,只有一个收集器会收到它。 SharedFlows 可以有一个缓冲区,可以为每个收集器重放一定数量的过去值。 StateFlow 的行为类似于具有 0 重放的 SharedFlow。每个新的收集器只能收集最新的值。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 2020-09-14
      • 1970-01-01
      • 2021-12-13
      • 1970-01-01
      • 2018-09-25
      • 2020-08-08
      相关资源
      最近更新 更多