DEV Community

Cover image for launchWhenCreated() vs launchWhenStarted() vs launchWhenResumed() vs repeatOnLifeCycle()
Vincent Tsen
Vincent Tsen

Posted on • Updated on • Originally published at


launchWhenCreated() vs launchWhenStarted() vs launchWhenResumed() vs repeatOnLifeCycle()

Investigating and experimenting various LifecycleCoroutineScope launchWhenX() and repeatOnLifeCycle() functions

In the previous article, we learned about LifeCycleCoroutineScope.launch(). However, there are a few additional functions in LifeCycleCoroutineScope:

  • launchWhenCreated()

  • launchWhenStarted()

  • launchWhenResumed()


The code usage looks like this:

fun DemoScreen() {  

    val lifeCycleScope = LocalLifecycleOwner.current.lifecycleScope

    Button(onClick = {  
        lifeCycleScope.launchWhenStarted {
Enter fullscreen mode Exit fullscreen mode

The benefit of using this launchWhenX() APIs is it can automatically start, suspend and resume the coroutines for you. The table below shows you in what lifecycle event, the coroutines are started, suspended, resumed and canceled.

launchWhenX functions When coroutines are started? When coroutines are suspended? When coroutines are resumed? When coroutines cancelled?
launchWhenCreated() ON_CREATE N/A N/A ON_DESTROY

Depends on when you call launchWhenX(), it automatically starts the coroutine when your current lifecycle state equals or above the target X lifecycle state.

The issue with launchWhenCreated() is when the lifecycle is destroyed, the LifeCycleCoroutineScope cancels all the coroutines. Since there are no more coroutines, there is nothing to be suspended or resumed.

To understand the lifecycle in detail, please read the following article:

Here is the summary of app visibility status corresponding to its lifecycle state:

Lifecycle States App Visibility Status
STARTED Visible at background
RESUMED Visible at foreground

Given all these functions above, it looks like launchWhenStarted() should be used because it doesn't waste any resources when your app is not visible. You can use launchWhenResumed(), but it suspends the coroutine when your app is still visible in the background, which we don't want.

launchWhenStarted() vs repeatOnLifeCycle()

But, wait! Isn't launchWhenStarted() same as repeatOnLifeCycle(Lifecycle.State.STARTED)?

fun DemoScreen() {  
    val lifeCycle = LocalLifecycleOwner.current.lifecycle
    val lifeCycleScope = LocalLifecycleOwner.current.lifecycleScope

    Button(onClick = {  
        lifeCycleScope .launch {
            lifeCycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
Enter fullscreen mode Exit fullscreen mode

Here is a summary of launchWhenStarted() vs repeatOnLifecycle(Lifecycle.State.STARTED) comparisons:

Launch Functions When coroutines are started? When coroutines are suspended? When coroutines are resumed? When coroutines are canceled?
repeatOnLifecycle(Lifecycle.State.STARTED) ON_START N/A N/A ON_STOP

As you can see, repeatOnLifecycle(Lifecycle.State.STARTED) doesn't suspend or resume the coroutines. When the lifecycle state moves below the STARTED state, it cancels all the coroutines. When it moves to STARTED state again, it starts the coroutine again.

On the other hand, launchWhenStarted() doesn't cancel the coroutines, but it suspends the coroutines instead.

Launch Functions App Is Not Visible (ON_STOP) App Becomes Visible (ON_START)
launchWhenStarted() Coroutines suspended Coroutines resumed
repeatOnLifecycle(Lifecycle.State.STARTED) Coroutines canceled Coroutines started again

In other words, what happens if the app moves to the background (app is not visible), then moves to the foreground (app is visible) again?

  • launchWhenStarted() suspends and resumes coroutines

  • repeatOnLifecycle(Lifecycle.State.STARTED) restarts the coroutines

If your coroutine count from 0 → 10000, repeatOnLifecycle(Lifecycle.State.STARTED) simply restarts the counter and starts from 0 again. Since launchWhenStarted() doesn't restart the coroutines, it appears it is the better option here.



Google advocates repeatOnLifecycle(Lifecycle.State.STARTED) over launchWhenStarted() because launchWhenStarted() is not safe to collect, it keeps emitting in the background when the UI is not visible. However, I don't see this behavior based on the experiment that I have done.

It seems to me both launchWhenStarted() and repeatOnLifecycle(Lifecycle.State.STARTED) are safe to collect. Depending on your need, launchWhenStarted() suspends and resumes the coroutine, and repeatOnLifecycle(Lifecycle.State.STARTED) restarts the coroutine.

You can also use them for collecting flow. See this article for details:

Source Code

GitHub Repository: Demo_CoroutineScope

Originally published at

Top comments (0)

Timeless DEV post...

Git Concepts I Wish I Knew Years Ago

The most used technology by developers is not Javascript.

It's not Python or HTML.

It hardly even gets mentioned in interviews or listed as a pre-requisite for jobs.

I'm talking about Git and version control of course.

One does not simply learn git