我有一个 Activity A,它是具有 StateFlow UI State 实现的 ViewModel,如 Android 文档中所述。
class A_ViewModel: ViewModel() {
private val _uiState = MutableStateFlow(UIState.None)
val uiState: StateFlow<UIState> = _uiState
fun onButtonClicked() {
_uiState.value = UIState.NavigateToB
}
}
class A_Activity: AppCompatActivity() {
private val viewModel = // getViewModel()
override fun onCreate() {
button.setOnClickListener {
viewModel.onButtonClicked()
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { uiState ->
when (uiState) {
is UIState.NavigateToB -> {
startActivity(Intent(this, B::class.java))
}
.
.
else -> { /* do nothing */ }
}
}
}
}
}
}
我面临的问题是,当我从 Activity B 返回到 Activity A 时,由于在 Activity A 的
viewModel.uiState.collect { }
中再次调用 onStart()
,因此会再次重播最新值 (UIState.NavigateToB
),而 Activity B 则为再次推出。
这似乎是一个非常微不足道的问题。但我无法为此想出安全的解决方案。
当然,有一些成功的解决方法,例如在活动 A 的
uiState.value = UIState.None
中设置 onStop()
。但我想不出一种优雅的方式来处理这个问题。
对于一次性事件,您可以使用通道而不是像这样的流:
private val _uiState:Channel<UIState> = Channel()
val uiState = _uiState.receiveAsFlow()
此外,如果您想要更大的灵活性,例如拥有多个消费者或保留最后一个值而不需要像这样回忆,您可以使用 MutableSharedFlow:
private val _uiState:MutableSharedFlow<UIState> = MutableSharedFlow(extraBufferCapacity=1)
val uiState:Flow<UIState> = _uiState
对于导航,我有一个独立的字段
SharedFlow
并且uiState
仅用于UI状态,例如:
在视图模型中
private val _goTo = MutableSharedFlow<NotPrefsRoute>(replay = 0, extraBufferCapacity = 1)
val goTo: SharedFlow<NotPrefsRoute> = _goTo
...
sealed class NotPrefsRoute {
object Back : NotPrefsRoute()
object NotificationSettings : NotPrefsRoute()
}
片段中
launchAndRepeatWithViewLifecycle {
viewModel.goTo.collect {
when (it) {
Back -> findNavController().popBackStack()
NotificationSettings -> activity?.openNotificationSettings()
}
}
}