Hi, great question. I did cover this in the article lightly but it’s easy to miss.
The issues with using the launchWhenX
functions are related to cancellation not when you call it nor is it related to receiving multiple events. All of them cancel when the lifecycle reaches the destroyed state. launchWhenStarted, however, pauses after onStop
before it cancels fully after onDestroy
. (launchWhenResumed
has a similar issue, but it just pauses earlier.) This makes it possible to receive an events / side effect after onStop
has been reached. This is bad for cases like navigation events which should only be performed between onStart and onStop.
It doesn't matter when you register the launchWhenX
lambda. You could register it in onCreate
if you wanted or even in onResume
, dealing with the repeated registration of course. The pausing of the dispatcher onStop
followed by the cancellation in onDestroy
is the problem.
I’d recommend you check out https://medium.com/swlh/deep-dive-into-lifecycle-coroutines-e7192312faf which describes the underlying mechanisms in the launchWhenX
functions.
You can see a simplified demonstration of events getting dropped here: https://gist.github.com/fergusonm/88a728eb543c7f6727a7cc473671befc
I’ve added some notes to the bottom of the gist that explain the issue. The TLDR though is that launchWhenStarted
pauses onStop but doesn’t cancel until onDestroy, leading to event loss and potential receipt of an even when it’s not safe to observe it.