吞噬
通过1.4更新,Kotlin Coroutines为我们带来了许多功能和改进。其中之一是引入SharedFlow
。基本上,我想说的只是“单一事件StateFlow
”。还记得单个事件LiveData
解决方法吗?好吧,在这里,您有它,但是100%Kotlin,而不再是解决方法。
如果您对更详细的解释更感兴趣,请在罗马·伊丽莎白(Roman Elizarov)带来的Github上关注this issue。
俄罗斯
问题
让我们假设我们有这种情况:
在ViewModel上进行了简单的计算之后,我们想决定将用户导航到哪个屏幕。让我们通过使用StateFlow
(MutableStateFlow
)来做到这一点:
private val _state = MutableStateFlow<State>(State.Idle)
val state: StateFlow<State> get() = _state
fun checkCalculations(){
if(calculationsSuccessful())
_state.value = State.MoveForward
else
_state.value = State.ShowError
}
直到这里,没有什么新鲜或有问题的。现在,让我们检查一下片段上正在发生的事情:
viewModel.state
.onEach{ state ->
when(state){
MoveForward -> navigateToNextScreen(addToBackstack = true)
else -> showError()
}
}.launchIn(lifecycleScope)
在这里似乎也很好。 但不是!
如果用户想返回,他们肯定会,但猜猜会发生什么:他们将重新列表重新列为他们已经已经存在的屏幕,然后向前移动导航,
每次按下后面按钮。
on par
汉克总是有一个适当性:
viewModel.state
.onEach{ state ->
when(state){
MoveForward -> {
navigateToNextScreen(addToBackstack = true)
viewModel.backtoIdleState()
}
else -> showError()
}
}.launchIn(lifecycleScope)
然后,在ViewModel
中:
fun backtoIdleState(){
_state.value = Idle
}
,但并不真正喜欢这些解决方案。
俄罗斯
让我们看看如何使用SharedFlow
(以及它的简单)解决问题。具有相同的情况,而是:
private val _state = MutableStateFlow<State>(State.Idle)
val state: StateFlow<State> get() = _state
fun checkCalculations(){
if(calculationsSuccessful())
_state.value = State.MoveForward
else
_state.value = State.ShowError
}
我们使用:
private val _events = MutableSharedFlow<Event>()
val events = _events.asSharedFlow()
fun checkCalculations(){
viewModelScope.launch(Dispatchers.Default){ //or whichever Dispatcher you need
if(calculationsSuccessful())
_events.emit(event)
else
_events.emit(event)
}
}
为了从SharedFlow
到emit()
,我们需要使用coroutine或suspend
函数。但这就是所有需要更改的(在这种情况下,命名)。
但是观察者方面发生了什么变化?什么都没有,绝对什么也没有。我们不必手动闲置,也不必更改它的一行,并且该错误已修复。如果用户返回,则将正常路由到以前的片段:
viewModel.state
.onEach{ event ->
when(event){
MoveForward -> navigateToNextScreen(addToBackstack = true)
else -> showError()
}
}.launchIn(lifecycleScope)
那是因为SharedFlow
已经是Flow
的实现。
ondestroy
SharedFlow
看起来不错,很有希望,就像许多最新的Coroutines API一样。您也可以将SharedFlow
用作纯EventBus
。即使这将使您的调试更加困难。有关SharedFlow
的更多信息和特殊操作,请访问他的官方文档here。