Bitwise DEVS
Bitwise DEVS

Reputation: 3449

Avoid repetitive launch when emitting value using Flow, StateFlow, SharedFlow

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))
        }
    }

}

Upvotes: 2

Views: 3699

Answers (1)

Tenfour04
Tenfour04

Reputation: 93649

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.

Upvotes: 1

Related Questions