I thought I was pretty solid with flows in kotlin, but I ran into some strange behavior in the code below.
In my view model, I set my MutableStateFlow to a default (I've also tried null) value so that the UI has something while the rest of the uiState is gathered.
private val _uiState: MutableStateFlow<MyUiState?> = MutableStateFlow(myUiStateDefault())
val uiState: StateFlow<MyUiState?> = _uiState.asStateFlow()
Upon initialization the uiState is meant to be updated with the new state. I've tried the assignment operator and the copy syntax.
.flowOn(Dispatchers.IO)
.collect {
it?.let {
_uiState.value = it // or _uiState.update { it.copy(...) }
}
}
However, for some reason, the value that is collected turns out to be the default/old value instead of the new value from the combine block.
combine(...) { w, x, y, z ->
...
MyUiState(...) // new value
}
In the fragment, I collect the state in this way.
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
I've tried calling the initialize function more than once and still the uiState does not get updated, and using Dispatchers.Main doesn't work.
Let me know if you have any questions. I suspect this could be a threading issue, but I'm not really sure either. I'm mostly confused at the fact my collect block is retrieving the myUiStateDefault value instead of the new MyUiState value created in the combine block.
Full code in my view model:
private val _uiState: MutableStateFlow<MyUiState?> = MutableStateFlow(myUiStateDefault())
val uiState: StateFlow<MyUiState?> = _uiState.asStateFlow()
init {
initUiState()
}
private fun initUiState() {
viewModelScope.launch(Dispatchers.IO) {
combine(...) { w, x, y, z ->
...
MyUiState(...) // new value
}
.flowOn(Dispatchers.IO)
.collect { // collects the default/old value here instead of the new value
it?.let {
_uiState.value = it // or _uiState.update { it.copy(...) }
}
}
}
}