0

I am observing inside a fragment the events of a sharedflow such as this:

myEvent.collectInLifeCycle(viewLifecycleOwner) { event ->
       when (state) {
         //check the event. The event emited form onStart is never reached here :(             
       }
}

Whereas in the viewmodel I have

private val _myEvent = MutableSharedFlow<MyEvent>()
    val myEvent: SharedFlow<MyEvent> = _myEvent

fun loadData() =
        viewModelScope.launch {
            getDataUseCase
                .safePrepare(onGenericError = { _event.emit(Event.Error(null)) })
                .onStart { _event.emit(Event.Loading) }
                .onEach { result ->
                    result.onSuccess { response -> 
                      _event.emit(Event.Something)
                    }
                }
                .launchIn(viewModelScope)
        }

So the problem is that only the Event.Something is the one being properly collected from the fragment, whereas _event.emit(Event.Loading) is not being collected... If I debug it goes to the onStart, but it is never called in the fragment.

General Grievance
  • 4,555
  • 31
  • 31
  • 45

1 Answers1

0

Your SharedFlow needs to have a replay so that collectors always get at least the most recent value. Otherwise, if you emit to the Flow before the collector is registered, it will never see anything emitted. Do this:

private val _myEvent = MutableSharedFlow<MyEvent>(replay = 1)

Personally, unless I'm missing some detail here that would change my mind, I would simplify all your code to avoid having to manually call loadData(). Something like this but I'm guessing a bit because I don't know all your types and functions.

val myEvent: SharedFlow<MyEvent> = flow {
    emit(Event.Loading)
    emitAll(
        getDataUseCase
            .transform { result ->
                result.onSuccess { response -> 
                    emit(Event.Something)
                }
            }
            .catch { error -> emit(Event.Error(null)) }
    )
}.shareIn(viewModelScope, SharingStarted.Lazily, replay = 1)
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • Thank you. It works perfectly. What I don't understand is why this same code I wrote above worked once but it needs a replay = 1 now to work. – Neus Cobos Feb 16 '23 at 07:34
  • It’s what’s called a race condition. The events have to happen in a certain order to work the way you expected, but there’s nothing enforcing one order or the other. The current level of CPU load or many other factors could change the outcome. In this case the two events are emission of the first item and registration of the first collector. – Tenfour04 Feb 16 '23 at 12:24