Android中如何收集多个状态流

Pri*_*a S 16 android kotlin android-livedata kotlin-flow

如何收集activity中的两个状态流?因为我只消耗了第一个流量。

例如,viewmodel内部是这样的:

class ExampleViewModel: ViewModel(){
    private val state = MutableStateFlow<HomeMainFragmentState>(HomeMainFragmentState.Init)
    private val products = MutableStateFlow<List<ProductEntity>>(mutableListOf())


    //to be consumed
    fun getState() : StateFlow<HomeMainFragmentState> = state
    fun getProducts() : StateFlow<List<ProductEntity>> = products
}
Run Code Online (Sandbox Code Playgroud)

然后在我看来是这样的:

private fun observe(){
      viewLifecycleOwner.lifecycleScope.launch {
      viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
            viewModel.getState().collect { state -> handleState(state) }
            viewModel.getProducts().collect{ products -> handleProducts(products) }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,只有第一个流被消耗,因为这种情况是“状态”产品从未被活动/片段消耗/执行。

如何解决这个问题?我还阅读了有关组合流程的信息,这是否意味着第二个流程取决于第一个流程的运行?

Wil*_*ran 20

CoroutineScope.launch您必须为每个收集器使用该函数。

viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
        launch {
            viewModel.getState().collect { state -> handleState(state) }
        }
        launch {
            viewModel.getProducts().collect{ products -> handleProducts(products) }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ten*_*r04 11

调用collectFlow 会挂起协程,直到 Flow 完成。对于 MutableStateFlow,只有在取消时才会完成。因此,通常,当您调用collectFlow 时,您不会在该调用下方的协程中执行任何其他操作。

如果您想单独收集每个流,则需要两个协程。

flowOnLifecycle函数将为您提供更清晰的代码,因此拥有两个协程并不那么痛苦:

private fun observe(){
    viewModel.getState()
        .flowOnLifecycle(Lifecycle.State.STARTED)
        .onEach { state -> handleState(state) }
        .launchIn(lifecycleScope)
    viewModel.getProducts()
        .flowOnLifecycle(Lifecycle.State.STARTED)
        .onEach { products -> handleProducts(products) }
        .launchIn(lifecycleScope)
}
Run Code Online (Sandbox Code Playgroud)

我还想提一下,像这样的函数名称getState在 Kotlin 中是不自然的,除非它们是重函数(即使它是必须计算某些内容的重函数,我更喜欢generateStatecalculateState)。使用属性更合适:

private val mutableState = MutableStateFlow<HomeMainFragmentState>(HomeMainFragmentState.Init)
val state: StateFlow<HomeMainFragmentState> get() = mutableState
Run Code Online (Sandbox Code Playgroud)

他们表示,在Kotlin 的未来版本中,可能会有更好的语法来公开不需要第二个属性的可变类的只读版本。像这样的东西:

private val state = MutableStateFlow<HomeMainFragmentState>(HomeMainFragmentState.Init)
    public get(): StateFlow<HomeMainFragmentState>
Run Code Online (Sandbox Code Playgroud)