0

I am migrating my Android project to Jetpack Compose. To do so, I emit events with StateFlow from a separate singleton class from Compose and collect it in my ViewModel. However, after one event is emitted nothing else is collected from the flow in my ViewModel:

  1. Emitting from my singleton class:
 /**
  * Class that emits bottom sheet events (expanded, collapsed, etc.).
  */
@Singleton
class BottomSheetEventProducer {
    private val _eventsFlow = MutableStateFlow<SheetEvent>(SheetEvent.Collapsed)
    val eventsFlow: Flow<SheetEvent> = _eventsFlow

    fun produceEvent(event: String) {
        var sheetEvent: SheetEvent = SheetEvent.Collapsed

        if (event.contains(SheetEvent.Collapsed.Const().value)) {
            sheetEvent = SheetEvent.Collapsed
        } else if (event.contains(SheetEvent.Expanded.Const().value)) {
            sheetEvent = SheetEvent.Expanded
        }

        Log.i("BottomSheetEventsSingleton", "produceEvent: $sheetEvent")
        _eventsFlow.value = sheetEvent
    }
}
  1. Collecting in the ViewModel:
    @HiltViewModel
    class FarmViewModel @Inject constructor(
        private val bottomSheetEvents: BottomSheetEvents
    ) : ViewModel() {
    init {
            viewModelScope.launch {
                bottomSheetEvents.eventsFlow
                    .collect { event ->
                        Log.i("FarmViewModel", "flow event: $event)")
                    }
            }
        }

The Log.i in collect only shows the initial value, and then nothing after.

IgorGanapolsky
  • 26,189
  • 23
  • 116
  • 147
  • What is `SheetEvent.RandomEvent`? Just an `object`? – ianhanniballake Mar 08 '23 at 03:47
  • What does the SheetEvent class look like? What do you mean by “unable to collect”? – Tenfour04 Mar 08 '23 at 05:16
  • @ianhanniballake It is a Compose `BottomSheetScaffold` event (expand or collapse). I created a sealed interface for it to pass through my `flow` – IgorGanapolsky Mar 08 '23 at 13:49
  • @Tenfour04 `SheetEvent` is a sealed interface with objects & data classes. What I mean is, the collector in my ViewModel only gets the first event, and then nothing else after (even though I see hundreds of events in Logcat emitted). – IgorGanapolsky Mar 08 '23 at 13:51
  • Only thing I can think of is that you don't actually have a singleton. You actually have multiple instances of your "singleton" class. Just a guess. But I don't know where you are logging events being logged...something is collecting it somewhere to be able to log it? – Tenfour04 Mar 08 '23 at 13:54
  • @Tenfour04 It is a Hilt singleton annotated with `@Singleton`. I see the events emitted from StateFlow in logcat, but not collected. – IgorGanapolsky Mar 08 '23 at 13:55
  • Where is the code that logs events being emitted if not in a collector somewhere? – Tenfour04 Mar 08 '23 at 13:56
  • @Tenfour04 It is bullet point #1 in my OP: `BottomSheetEventProducer` – IgorGanapolsky Mar 08 '23 at 14:00
  • Are you testing this by repeatedly calling `produceEvent` in a loop? If you change a StateFlow's value many times on the same thread that you are collecting on (in this case the main thread), then your collector will only see the last emission because a StateFlow is **conflated**, and the collector doesn't have a chance to run until the code running on the thread relinquishes the thread by completing or suspending. StateFlow or any other conflated Flow is really not suitable for events if you don't want events to be dropped. – Tenfour04 Mar 08 '23 at 14:33
  • Yes I have tested in a loop, the `collect` only gets the first value from the Flow and nothing else after that. – IgorGanapolsky Mar 08 '23 at 14:34
  • Try calling `yield()` after each call to `produceEvents()` in your loop (assuming you are calling it in a coroutine). But as I mentioned in my edited comment, StateFlow or any other conflated Flow is not suitable for an event queue where it is not OK for events to be dropped. – Tenfour04 Mar 08 '23 at 14:36
  • If StateFlow is not suitable for this case, what is an alternative? – IgorGanapolsky Mar 08 '23 at 14:39

0 Answers0