Flow onEach/Collect在从片段返回时被多次调用
我使用Flow而不是LiveData来收集片段中的数据。在片段A中,我观察(或者更确切地说是收集)片段的onView中的数据如下所示:
lifecycleScope.launchWhenStarted {
availableLanguagesFlow.collect {
languagesAdapter.setItems(it.allItems, it.selectedItem)
}
}
问题。然后,当我转到片段B,然后返回到片段A时,我的Collect函数被调用两次。如果我再次访问片段B并返回到A,则收集函数被调用3次。以此类推。
解决方案
原因
它的发生是因为tricky Fragment lifecycle。当您从片段B返回到片段A时,片段A会重新连接。结果,片段的onViewCreated被第二次调用,并且您第二次观察到流的相同实例。换句话说,现在您有一个具有两个观察者的流,当该流发出数据时,就会调用其中两个观察者。
片段的解决方案%1
在片段的onViewCreated中使用viewLifecycleOwner。更具体地说,使用viewLifecycleOwner.lifecycleScope.launch而不是lifecycleScope.如下所示:
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
availableLanguagesFlow.collect {
languagesAdapter.setItems(it.allItems, it.selectedItem)
}
}
活动的解决方案2
在活动中,您只需在onCreate中收集数据。
lifecycleScope.launchWhenStarted {
availableLanguagesFlow.collect {
languagesAdapter.setItems(it.allItems, it.selectedItem)
}
}
其他信息
- LiveData也是如此。见帖子here。也请勾选this article。
- 使用Kotlin扩展使代码更干净:
分机:
fun <T> Flow<T>.launchWhenStarted(lifecycleOwner: LifecycleOwner) {
lifecycleOwner.lifecycleScope.launchWhenStarted {
this@launchWhenStarted.collect()
}
}
在片段onView Created中:
availableLanguagesFlow
.onEach {
//update view
}.launchWhenStarted(viewLifecycleOwner)
更新
我更喜欢使用NowrepeatOnLifecycle
,因为它会在生命周期低于状态(在我的例子中是onStop)时取消正在进行的协程。如果没有repeatOnLifecycle
,则onStop时将暂停采集。签出this article。
fun <T> Flow<T>.launchWhenStarted(lifecycleOwner: LifecycleOwner)= with(lifecycleOwner) {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED){
try {
this@launchWhenStarted.collect()
}catch (t: Throwable){
loge(t)
}
}
}
}
相关文章