'Kotlin Flow - Some emitted events not received when collect
I am using MutableStateFlow
. My flow type is sealed class with different states (Loading, Success, Error, etc). Initial value of my flow is empty:
private val _updateDepartmentsState = MutableStateFlow<DepartmentFetchState>(DepartmentFetchState.Empty)
In my repository I'm emitting different states. For example :
suspend fun updateDepartments() {
_updateDepartmentsState.emit(DepartmentFetchState.Loading)
try {
remoteDataSource.updateDepartments()
// here some code
_updateDepartmentsState.emit(DepartmentFetchState.Success(data))
} catch(e: NetworkException) {
_updateDepartmentsState.emit(DepartmentFetchState.Error)
}
}
Also in my repository I have read only flow:
val updateDepartmentsState = _updateDepartmentsState.asStateFlow()
In view model I'm collect flow via interactor. My code inside view model:
updateDepartmentsState.emitAll(
interactor
.updateState // state flow (`updateDepartmentsState` ) from repository via interactor
.map { state->
when (state) {
DepartmentFetchState.Loading -> {}
DepartmentFetchState.Error-> {}
...
}
}.also {
interactor.updateDepartments() // call updateDepartments() from repository via interator
}
As I understand from the documentation, after we have completed the collect, we must get the initial value. But it doesn't happen. Moreover, I do not receive state DepartmentFetchState.Loading
. I receive only last state - DepartmentFetchState.Success
.
But the most interesting thing is that if I re-call the code from the view model (for example, when updating by swipe), then I get the DepartmentFetchState.Loading
state, and then the DepartmentFetchState.Success
state, as expected.
I don't understand why on the first call, the initial value that I set when initializing the flow and the DepartmentFetchState.Loading
state are lost.
Please, help me(
Solution 1:[1]
What you have described is the intended purposes of StateFlow
.
Moreover, I do not receive state
DepartmentFetchState.Loading
. I receive only last state -DepartmentFetchState.Success
.
This is because StateFlow is a state-holder observable flow that emits the current and new state updates to its collectors. And by the time you start collecting the flow your updateDepartments()
has already been finished with a DepartmentFetchState.Success
. Means that from this moment onward when you collect the flow, the current state is DepartmentFetchState.Success
.
And then:
But the most interesting thing is that if I re-call the code from the view model (for example, when updating by swipe), then I get the
DepartmentFetchState.Loading
state, and then theDepartmentFetchState.Success
state, as expected.
When you re-call the code you receive the result as expected, that's because you have been collecting from the flow as your updateDepartments()
execute it will emit the current state DepartmentFetchState.Loading
, and then DepartmentFetchState.Success
respectively.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Sovathna Hong |