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



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

为了便于理解:

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

private val basicViewModel: basicViewModel by navGraphViewModels(R.id.basic_graph) { defaultViewModelProviderFactory }

此ViewModel具有像以下一样声明的MutableStateFlow属性

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

然后,我使用导航图在导航中声明了FragmentAFragmentB,导航图类似地调用属性,比如这个

basicViewModel.basicProperty
.filterNotNull()
.mapNotNull { it.innerProperty}
.onEach { doSomething(it) }
.launchIn(viewLifecycleOwner.lifecycleScope)

这一切看起来都很好,但当我导航到FragmentA时,BasicProperty加载流(从WebApi加载数据(,然后我导航到FragmentB,流再次加载,而不是调用已经加载的数据,因为重载,它在应用程序中看起来有点滞后

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

您的_basicProperty是一个热门的StateFlow,但您从未使用它来收集任何东西。您公开的属性basicProperty是一个冷流,因此每个收集它的订阅者都将开始新的冷流运行。这些冷流中的每一个都会将其更新发布到MutableStateFlow,因此在这一点上,其状态是不可预测的,因为它显示了共享冷流的任何收集器正在做的最新事情。

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

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

在每个Fragment出现并收集它之前,您的原始代码不会启动流。但此代码对stateIn的调用在viewModelScope中启动流一次(在这种情况下,由于Eagerly参数的原因,会立即启动流(。

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

最新更新