在 ViewModel 中收集流。是否需要 repeatOnLifeCycle?
Collecting Flows in ViewModel. Is repeatOnLifeCycle needed?
到目前为止,我曾经像这样在 activity/fragment 或 ViewModel 中收集我的流程
Activity/Fragment
lifecycleScope.launch {
myViewModel.readTokenCredentials().collect { data -> /* do something */ }
}
视图模型
viewModelScope.launch {
prefsRepo.readTokenCredentials().collect { data -> /* do something */ }
}
现在 Google 开发人员 tell 我们认为这不是收集流的安全方法,因为它可能导致内存泄漏。相反,他们建议将集合包装在 lifecycle.repeatOnLifecycle
中,以便在 Activities/Fragments.
中进行流收集
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
myViewModel.readTokenCredentials().collect { data -> /* do something */ }
}
}
我的问题是:
为什么在视图模型中收集流时我不能将 repeatOnLifecycle
与 viewModelScope
一起使用?当然,我知道视图模型不是生命周期感知的,但也许 viewModelScope
不太可能在流收集期间引入内存泄漏?
不可能重复生命周期,因为 ViewModel 没有重复的生命周期。启动一次,销毁一次。
我不认为内存泄漏是一个准确的术语,用于描述在 Fragment 不在屏幕上时继续收集 Flow 时发生的情况。它只是导致它的上游 Flow 无缘无故地继续发射,但发射的项目将被垃圾收集。简直是浪费activity。如果您也在收集器中更新 UI,就会出现危险,因为您可能会不小心更新屏幕外的视图。
在 ViewModel 中,您无缘无故地从 Flows 中收集数据的风险相同。为避免这种情况,您可以使用 stateIn
或 shareIn
和 WhileSubscribed
值。然后在下游没有东西收集的时候就停止收集了。如果您在从这些 SharedFlow 和 StateFlow 收集的 Activity 和 Fragment 中使用 repeatOnLifecycle
,那么一切都会得到处理。
例如:
val someFlow = prefsRepo.readTokenCredentials()
.map { data -> // doSomething }
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), 1)
并收集到UI层。如果 UI 没有什么可收集的,那么为什么流首先存在?我想不出一个好的反例。 ViewModel 旨在准备模型以供查看,而不是执行从未见过的工作。
到目前为止,我曾经像这样在 activity/fragment 或 ViewModel 中收集我的流程
Activity/Fragment
lifecycleScope.launch {
myViewModel.readTokenCredentials().collect { data -> /* do something */ }
}
视图模型
viewModelScope.launch {
prefsRepo.readTokenCredentials().collect { data -> /* do something */ }
}
现在 Google 开发人员 tell 我们认为这不是收集流的安全方法,因为它可能导致内存泄漏。相反,他们建议将集合包装在 lifecycle.repeatOnLifecycle
中,以便在 Activities/Fragments.
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
myViewModel.readTokenCredentials().collect { data -> /* do something */ }
}
}
我的问题是:
为什么在视图模型中收集流时我不能将 repeatOnLifecycle
与 viewModelScope
一起使用?当然,我知道视图模型不是生命周期感知的,但也许 viewModelScope
不太可能在流收集期间引入内存泄漏?
不可能重复生命周期,因为 ViewModel 没有重复的生命周期。启动一次,销毁一次。
我不认为内存泄漏是一个准确的术语,用于描述在 Fragment 不在屏幕上时继续收集 Flow 时发生的情况。它只是导致它的上游 Flow 无缘无故地继续发射,但发射的项目将被垃圾收集。简直是浪费activity。如果您也在收集器中更新 UI,就会出现危险,因为您可能会不小心更新屏幕外的视图。
在 ViewModel 中,您无缘无故地从 Flows 中收集数据的风险相同。为避免这种情况,您可以使用 stateIn
或 shareIn
和 WhileSubscribed
值。然后在下游没有东西收集的时候就停止收集了。如果您在从这些 SharedFlow 和 StateFlow 收集的 Activity 和 Fragment 中使用 repeatOnLifecycle
,那么一切都会得到处理。
例如:
val someFlow = prefsRepo.readTokenCredentials()
.map { data -> // doSomething }
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), 1)
并收集到UI层。如果 UI 没有什么可收集的,那么为什么流首先存在?我想不出一个好的反例。 ViewModel 旨在准备模型以供查看,而不是执行从未见过的工作。