I am migrating from LiveData
to Coroutine Flows specifically StateFlow
and SharedFlow
. Unfortunately emitting values should run on a CoroutineScope thus you have this ugly repetitive code viewModelScope.launch
when using it inside a ViewModel. Is there an optimal way of emitting values from this?
class MainSharedViewModel : BaseViewModel() {
private val mainActivityState = MutableSharedFlow<MainActivityState>()
fun getMainActivityState(): SharedFlow<MainActivityState> = mainActivityState
fun setTitle(title: String){
viewModelScope.launch {
mainActivityState.emit(ToolbarTitleState(title))
}
}
fun filterData(assetName: String){
viewModelScope.launch {
mainActivityState.emit(AssetFilterState(assetName))
}
}
fun limitData(limit: Int){
viewModelScope.launch {
mainActivityState.emit(AssetLimitState(limit))
}
}
}
CodePudding user response:
Use tryEmit()
instead of emit()
. tryEmit()
is non-suspending. The reason it's "try" is that it won't emit if the flow's buffer is currently full and set to SUSPEND instead of dropping values when full.
Note, you have no buffer currently because you left replay
as 0. You should keep a replay of at least 1
so values aren't missed when there is a configuration change on your Activity/Fragment.
Example:
fun setTitle(title: String){
mainActivityState.tryEmit(ToolbarTitleState(title))
}
Alternatively, you can use MutableStateFlow, which always has a replay of 1 and can have its value set by using value =
, just like a LiveData.