如何在 Android 中收集多个状态流
How to collect multiple state flow in Android
如何在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
}
然后在我看来是这样的:
private fun observe(){
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
viewModel.getState().collect { state -> handleState(state) }
viewModel.getProducts().collect{ products -> handleProducts(products) }
}
}
}
问题是,只消耗了第一个流量,对于这种情况是 'state',products从来没有 consumed/executed activity/fragment.
如何解决这个问题?
我还阅读了有关合并流程的内容,这是否意味着第二个流程取决于第一个流程 运行?
在 Flow 上调用 collect
会暂停协程,直到 Flow 完成。对于 MutableStateFlow,它只有在被取消时才会完成。因此,通常,当您在流程上调用 collect
时,您不会在该调用下的协程中执行任何其他操作。
如果您想单独收集这些流中的每一个,则需要两个协程。
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)
}
我还想提一下,像 getState
这样的函数名称在 Kotlin 中是不自然的,除非它们是重函数(即使它是一个必须计算某些东西的重函数,我更喜欢 generateState
或 calculateState
)。使用 属性:
更合适
private val mutableState = MutableStateFlow<HomeMainFragmentState>(HomeMainFragmentState.Init)
val state: StateFlow<HomeMainFragmentState> get() = mutableState
他们说在 未来 版本的 Kotlin 中,可能会有更好的语法来公开可变 class 的只读版本,它不会' 需要第二个 属性。像这样:
private val state = MutableStateFlow<HomeMainFragmentState>(HomeMainFragmentState.Init)
public get(): StateFlow<HomeMainFragmentState>
您必须为每个收集器使用 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) }
}
}
}
如何在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
}
然后在我看来是这样的:
private fun observe(){
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
viewModel.getState().collect { state -> handleState(state) }
viewModel.getProducts().collect{ products -> handleProducts(products) }
}
}
}
问题是,只消耗了第一个流量,对于这种情况是 'state',products从来没有 consumed/executed activity/fragment.
如何解决这个问题? 我还阅读了有关合并流程的内容,这是否意味着第二个流程取决于第一个流程 运行?
在 Flow 上调用 collect
会暂停协程,直到 Flow 完成。对于 MutableStateFlow,它只有在被取消时才会完成。因此,通常,当您在流程上调用 collect
时,您不会在该调用下的协程中执行任何其他操作。
如果您想单独收集这些流中的每一个,则需要两个协程。
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)
}
我还想提一下,像 getState
这样的函数名称在 Kotlin 中是不自然的,除非它们是重函数(即使它是一个必须计算某些东西的重函数,我更喜欢 generateState
或 calculateState
)。使用 属性:
private val mutableState = MutableStateFlow<HomeMainFragmentState>(HomeMainFragmentState.Init)
val state: StateFlow<HomeMainFragmentState> get() = mutableState
他们说在 未来 版本的 Kotlin 中,可能会有更好的语法来公开可变 class 的只读版本,它不会' 需要第二个 属性。像这样:
private val state = MutableStateFlow<HomeMainFragmentState>(HomeMainFragmentState.Init)
public get(): StateFlow<HomeMainFragmentState>
您必须为每个收集器使用 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) }
}
}
}