'How to launch lifecycle.whenResumed coroutine immediately so flow-collection starts before returning?

I listen to a flow in whenResumed, so events are only collected while app is resumed. However I would like to ensure that I have started listeners before I run code that might send events that must be collected.

init {
    lifecycleScope.launchWhenResumed {
        stateUpdates.collect { onUpdate(it) }
    }
    // Now do stuff that might trigger event, which I want to collect above.
    // This does not have to be in init {}, an initialize() is fine
    doMyThing()
}

I know I can use a sharedFlow with a cache, but for my usage-case, a cache might be problematic.

--

I know I can do the following, where line 1 is executed immediately, but here again line 2 is dispatched and thus executed later:

CoroutineScope(Dispatchers.Main).launch(start = CoroutineStart.UNDISPATCHED) {
    // 1
    lifecycle.whenResumed {
        // 2
    }
}

==== Update 3. March 2022

Thanks IR42 for good info on option. What I was actually after is scheduling many different types of collectors, and then do my thing.

init {
    lifecycleScope.launchWhenResumed {
        launch { stateUpdates1.collect { onUpdate1(it) } }
        launch { stateUpdates2.collect { onUpdate2(it) } }
        launch { stateUpdates3.collect { onUpdate3(it) } }
        launch { stateUpdates4.collect { onUpdate4(it) } }
        launch { stateUpdates5.collect { onUpdate5(it) } }
    }
    // Now do stuff that might trigger event, which I want to collect above.
    // This does not have to be in init {}, an initialize() is fine
    doMyThing()
}   

I would like a nice idiomatic way of doing this. I don't see how to do that with onSubscription(), though I appreciate the input as it was new to me.



Solution 1:[1]

You can use onSubscription

lifecycleScope.launchWhenResumed {
    stateUpdates
        .onSubscription { 
            // Do my thing, that might result in state-update 
        }
        .collect { onUpdate(it) }
}

Solution 2:[2]

Instead of doing this:

runBlocking {
    lifecycleScope.launchWhenResumed {
        stateUpdates.collect { onUpdate(it) }
    }
    yield()
}

Do this, which is less fragile:

lifecycleScope.launchWhenResumed {
    yield()
    stateUpdates.collect { onUpdate(it) }
}

It's still a bit fragile, though, because it relies on the order coroutines were submitted.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Tenfour04