【问题标题】:StateFlow is emitting every time the activity paused and resumed每次活动暂停和恢复时,StateFlow 都会发出
【发布时间】:2021-09-08 11:06:57
【问题描述】:

我有一个状态流,一旦 HTTP 请求与响应一起返回,就会发出一个值,该值将在 Activity 中显示为列表,我正在使用 Kotlin 协程 StateFlow 在 ViewModel 和 Activity 之间进行通信。

我正在使用androidx生命周期repeatOnLifecycle这样的函数:

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.successFlow.collect { binding.recyclerView.adapter = ExampleAdapter(it) }
    }
}

这在开始时工作得很好,但后来我意识到每次用户转到另一个屏幕并返回到前一个屏幕时,状态流都会重新发送在这种情况下会丢失列表状态的值,例如,如果用户滚动到列表中的项目10,然后转到另一个屏幕并返回列表将滚动到位置0,因为再次调用setAdapter 方法,使用LiveData 时不是这种情况。

现在我还需要处理StateFlow 状态和配置状态,我尝试使用distinctUntilChanged 方法,但正如文档中所说的Applying 'distinctUntilChanged' to StateFlow has no effect

这里的问题是如何使用StateFlow 实现相同的LiveData 行为。

【问题讨论】:

    标签: android kotlin kotlin-coroutines kotlin-flow


    【解决方案1】:

    您遇到了recently described in a Medium post 的问题。每个流集合都重新开始,并且将一次又一次地接收该值,即使它没有更改。另一方面,LiveData 知道每个观察者看到的数据的版本,并且只会发送已再次发布的数据。

    解决问题的一个简单方法是将数据存储在某处并检查它是否已更改。您还可以使用flowWithLifecycle() 收集流并对其执行distinctUntilChanged()(请注意在此之后使用缓冲运算符,否则值发射可能会丢失,如上面链接的帖子中所述)。

    看起来像这样:

    viewModel.successFlow.flowWithLifecycle(lifecycle).distinctUntilChanged().onEach {
        binding.recyclerView.adapter = ExampleAdapter(it)
    }.launchIn(lifecycleScope)
    
    

    但是,我认为您不应该每次数据更改时都更换适配器!你应该这样做:

    (binding.recyclerView.adapter as ListAdapter<*,*>).submitList(it)
    

    (当然,您应该使用 ListAdapter 才能工作)

    这样,当新数据到达时,无论是相同数据还是不同数据,都不会受到干扰。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-21
      相关资源
      最近更新 更多