每次活动暂停和恢复时 StateFlow 都会发出信号

Moh*_*dan 10 android kotlin kotlin-coroutines kotlin-flow

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

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

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

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

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

这里的问题是我如何LiveData使用StateFlow.

niq*_*eco 5

您遇到了最近在 Medium 帖子中描述的问题。每个流集合都会重新开始,并且会一次又一次地接收该值,即使该值没有发生变化。LiveData另一方面,知道每个观察者已经看到了哪个版本的数据,并且只会发送已经再次发布的数据。

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

它看起来像这样:

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

Run Code Online (Sandbox Code Playgroud)

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

(binding.recyclerView.adapter as ListAdapter<*,*>).submitList(it)
Run Code Online (Sandbox Code Playgroud)

(当然,您应该使用 ListAdapter 才能实现此目的)

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