防止从另一个 Activity 返回后重放 StateFlow

问题描述 投票:0回答:2

我有一个 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()
。但我想不出一种优雅的方式来处理这个问题。

android kotlin lifecycle kotlin-stateflow
2个回答
2
投票

对于一次性事件,您可以使用通道而不是像这样的流:

 private val _uiState:Channel<UIState> = Channel()
 val uiState = _uiState.receiveAsFlow()

此外,如果您想要更大的灵活性,例如拥有多个消费者或保留最后一个值而不需要像这样回忆,您可以使用 MutableSharedFlow:

 private val _uiState:MutableSharedFlow<UIState> = MutableSharedFlow(extraBufferCapacity=1)
 val uiState:Flow<UIState> = _uiState

1
投票

对于导航,我有一个独立的字段

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() } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.