老專案常常把導航或其他一次性事件寫成 LiveData 旗標。
導航觸發後,清除導航旗標 LiveData 以避免前一頁留存錯誤的旗標。
fun clearNavigateLiveData() {
_navigateToDetail.value = false
}
或
fun clearErrorMessage() {
_errorMessage.value = null
}
你會看到專案中常這樣控制一次性事件:
ViewModel:
private val _navigateToDetail = MutableLiveData<Boolean>()
val navigateToDetail: LiveData<Boolean> = _navigateToDetail
按下按鈕:
_navigateToDetail.value = true
Fragment:
viewModel.navigateToDetail.observe(viewLifecycleOwner) { navigate ->
if (navigate == true) {
findNavController().navigate(...)
viewModel.clearNavigateToDetail()
}
}
這是一個消耗(消費)並重置的 pattern。
但他其實不是一個 UI 狀態。發出導航行為後就就消滅,不需要把這個狀態長期保存。
依現代框架:
先定義 UI Effect:
sealed interface DetailUiEffect {
data object NavigateBack : DetailUiEffect
}
在 ViewModel 內使用 emit 把值送入 Flow:
class DetailViewModel : ViewModel() {
private val _effect =
MutableSharedFlow<DetailUiEffect>()
val effect = _effect.asSharedFlow()
fun save() {
viewModelScope.launch {
// save success
_effect.emit(
DetailUiEffect.NavigateBack
)
}
}
}
UI:
lifecycleScope.launch {
viewModel.effect.collect { effect ->
when (effect) {
DetailUiEffect.NavigateBack ->
findNavController().popBackStack()
}
}
}