在 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 */ }
    }   
}

我的问题是:

为什么在视图模型中收集流时我不能将 repeatOnLifecycleviewModelScope 一起使用?当然,我知道视图模型不是生命周期感知的,但也许 viewModelScope 不太可能在流收集期间引入内存泄漏?

不可能重复生命周期,因为 ViewModel 没有重复的生命周期。启动一次,销毁一次。

我不认为内存泄漏是一个准确的术语,用于描述在 Fragment 不在屏幕上时继续收集 Flow 时发生的情况。它只是导致它的上游 Flow 无缘无故地继续发射,但发射的项目将被垃圾收集。简直是浪费activity。如果您也在收集器中更新 UI,就会出现危险,因为您可能会不小心更新屏幕外的视图。

在 ViewModel 中,您无缘无故地从 Flows 中收集数据的风险相同。为避免这种情况,您可以使用 stateInshareInWhileSubscribed 值。然后在下游没有东西收集的时候就停止收集了。如果您在从这些 SharedFlow 和 StateFlow 收集的 Activity 和 Fragment 中使用 repeatOnLifecycle,那么一切都会得到处理。

例如:

val someFlow = prefsRepo.readTokenCredentials()
    .map { data -> // doSomething }
    .shareIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), 1)

并收集到UI层。如果 UI 没有什么可收集的,那么为什么流首先存在?我想不出一个好的反例。 ViewModel 旨在准备模型以供查看,而不是执行从未见过的工作。