共享流的使用
#android #flow #coroutines

吞噬

通过1.4更新,Kotlin Coroutines为我们带来了许多功能和改进。其中之一是引入SharedFlow。基本上,我想说的只是“单一事件StateFlow”。还记得单个事件LiveData解决方法吗?好吧,在这里,您有它,但是100%Kotlin,而不再是解决方法。
如果您对更详细的解释更感兴趣,请在罗马·伊丽莎白(Roman Elizarov)带来的Github上关注this issue

俄罗斯

问题

让我们假设我们有这种情况:

在ViewModel上进行了简单的计算之后,我们想决定将用户导航到哪个屏幕。让我们通过使用StateFlowMutableStateFlow)来做到这一点:

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)
    }
}

为了从SharedFlowemit(),我们需要使用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