Home > Software engineering >  Avoid repetitive launch when emitting value using Flow, StateFlow, SharedFlow
Avoid repetitive launch when emitting value using Flow, StateFlow, SharedFlow

Time:02-28

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.

  • Related