Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SharedFlow : mapLatest not getting triggered

Let's make this simple. I've one MutableSharedFlow named sortOrder in my ViewModel.

private val sortOrder = MutableSharedFlow<String>(
    replay = 0,
    extraBufferCapacity = 1
)

I've a mapLatest connected to the sortOrder to refresh data whenever the sortOrder changed.

val data = sortOrder.mapLatest {
    Timber.d("Sort order changed to $it")
    "Sort order is $it"
}

I have an observer listening to data in the activity.

viewModel.data.asLiveData().observe(this) {
    Timber.d("onCreate: New data is $it")
}

and finally, I change the sortOrder in ViewModel's init method

init {
    sortOrder.tryEmit("year")
}

but even after changing the sortOrder value, the mapLatest not getting triggered. Any idea why?

I am using MutableSharedFlow to control the replay property to prevent executing mapLatest body every time I rotate the screen (or when the activity recreated).

Full Source Code

  • Full Activity : TestActivity.kt
  • Full ViewModel : TestViewModel.kt

PS: I am new to Flow APIs

like image 475
theapache64 Avatar asked Sep 17 '25 12:09

theapache64


1 Answers

The issue seems to be the order in which you're emitting to the flow and collecting from it (with viewModel.data.asLiveData().observe(...)). Since you emit (with tryEmit) in the construction of the view model, so you cannot be observing at that point. The implementation is in theory the same as this:

val sortOrder = MutableSharedFlow<String>(
    replay = 0,
    extraBufferCapacity = 1
)

val data = sortOrder.mapLatest {
    Timber.d("Sort order changed to $it")
    "Sort order is $it"
}

sortOrder.tryEmit("year")

data.asLiveData().observe(this) {
    Timber.d("onCreate: New data is $it")
}

The solution depends on your wanted behavior:

If you are okay about the same value potentially be emitted to new collectors, you can simply set reply = 1 (and then extraBufferCapacity can be set to 0).

The other solution is to make sure tryEmit isn't called until after viewModel.data.asLiveData().observe(...) is called and make sure that the activity is at least in resumed state when calling tryEmit or else the value is ignored.

like image 152
Anigif Avatar answered Sep 19 '25 02:09

Anigif