在两个片段之间共享 ViewModel 中 MutableStateFlow 的冷流

qki*_*qki 3 navigation android viewmodel kotlin kotlin-flow

我在两个片段之间共享 MutableStateFlow 属性时遇到问题。

为了使其易于理解:

BasicViewModel由于导航图的实现,我有一个应该始终是两个片段的一个实例

private val basicViewModel: basicViewModel by navGraphViewModels(R.id.basic_graph) { defaultViewModelProviderFactory }
Run Code Online (Sandbox Code Playgroud)

这个 ViewModel 有一个MutableStateFlow像这样声明的属性

    private val _basicProperty = MutableStateFlow<BasicClass?>(null)
    val basicProperty : Flow<BasicClass?> = _basicId
        .filterNotNull()
        .flatMapConcat { someRepository.getBasicProperty(it) }
        .onEach { _basicProperty.value = it }
        .catch {  }
Run Code Online (Sandbox Code Playgroud)

然后,我使用导航图在导航中FragmentA声明FragmentB,该导航图类似地调用该属性,如下所示

        basicViewModel.basicProperty
        .filterNotNull()
        .mapNotNull { it.innerProperty}
        .onEach { doSomething(it) }
        .launchIn(viewLifecycleOwner.lifecycleScope)
Run Code Online (Sandbox Code Playgroud)

一切看起来都很好,但是当我导航到FragmentABasicProperty 加载流程(从 WebApi 加载数据)时,我导航到FragmentB 并再次加载流程,而不是调用已加载的数据,在 App 中,由于重新加载,它看起来有点滞后

问题:我应该做什么/更改才能从BasicViewModelin 中获取已有的数据FragmentB?

Ten*_*r04 5

你_basicProperty是一个热门的 StateFlow,但你从来没有用它来收集任何东西。您公开的属性basicProperty是冷流,因此收集它的每个订阅者都将启动新的冷流运行。每个冷流都会将其更新发布到 MutableStateFlow,因此此时其状态是不可预测的,因为它显示共享冷流的任何收集器正在执行的最新操作。

我认为您想要的是共享一个执行流程。因此,您应该有一个正在执行连接的 StateFlow,如下所示:

val basicProperty : StateFlow<BasicClass?> = _basicId
    .filterNotNull()
    .flatMapConcat { someRepository.getBasicProperty(it) }
    .catch {  }
    .stateIn(viewModelScope, SharingStarted.Eagerly, null)
Run Code Online (Sandbox Code Playgroud)

您的原始代码不会执行任何操作来启动流程,直到每个片段出现来收集它。但是此代码的调用会stateIn在 中启动一次流程viewModelScope(在本例中由于Eagerly参数而立即启动)。

现在这个流程只运行一次。您仍然可以让每个片段运行自己的下游流,就像您已经做的那样。