In my app, I have a UIState sealed class to represent the UI state.
sealed class UIState<T> {
class ShowLoading<T> : UIState<T>()
class HideLoading<T> : UIState<T>()
class ShowEmptyData<T> : UIState<T>()
class ShowData<T>(val data: T) : UIState<T>()
class ShowError<T>(val errorUIState: ErrorUIState) : UIState<T>()
}
Accordingly, my viewmodel code is:
someRequest.apply { response ->
when (response) {
is ApiResponse.Success -> {
_uiStateFlow.value = (UIState.HideLoading()) // First, hide the loading
// Do some work
_uiStateFlow.value = (UIState.ShowData(data))
}
is ApiResponse.Error -> {
_uiStateFlow.value = (UIState.ShowError(error))
}
}
}
In this case, most of the time my hideLoading state doesn't collect, it drops because the success/error state comes immediately after hideLoading, and my UI doesn't collect it. E.g. If I will delay success/error states set for 100ms, hideLoading will be collected from the UI.
I use collect instead of collectLatest.
But then I've found out, that when I change the set value part to update {}, the UI collects all the states.
someRequest.apply { response ->
when (response) {
is ApiResponse.Success -> {
_uiStateFlow.update { (UIState.HideLoading()) } // First, hide the loading
// Do some work
_uiStateFlow.update { (UIState.ShowData(data)) }
}
is ApiResponse.Error -> {
_uiStateFlow.update { (UIState.ShowError(error)) }
}
}
}
So what's the difference between .value and update and why this one works pretty well? Thank you.
P.S. I've used emit() as well. Under the hood it's the same as .value, it's just a suspend function.