GlobalScope vs viewModelScope vs lifecycleScope vs rememberCoroutineScope
Tags: android, kotlin, beginners, jetpackcompose
Published: 2022-12-16 23:00:00

**Simple app to demonstrate Android Pre-defined Coroutine Scopes Comparisons - when will these Coroutine Scopes be cancelled?**

This is part of the Kotlin coroutines series:
* [Part 1 - Kotlin Coroutines Basics - Simple Android App Demo](https://vtsen.hashnode.dev/kotlin-coroutines-basics-simple-android-app-demo)    
* [Part 2 - kotlinx.coroutines.delay() vs Thread.sleep()](https://vtsen.hashnode.dev/kotlinxcoroutinesdelay-vs-threadsleep)   
* **Part 3 - GlobalScope vs viewModelScope vs lifecycleScope vs rememberCoroutineScope**  
* [Part 4 - launchWhenCreated() vs launchWhenStarted() vs launchWhenResumed() vs repeatOnLifeCycle()](https://vtsen.hashnode.dev/launchwhencreated-vs-launchwhenstarted-vs-launchwhenresumed-vs-repeatonlifecycle)

The whole point of having these Android pre-defined coroutine scopes is it automatically cancels all the coroutines that are launched in this scope, so you don't need to explicitly cancel them. The exception is `GlobalScope` survives until process death.

## GlobalScope

`GlobalScope` never gets canceled, even when the activity is destroyed/finished. If you launch a coroutine with `GlobalScope`, the coroutine runs until it ends. If the coroutine doesn't end, it will keep running either in the background or foreground until the process is killed.

```kotlin
GlobalScope.launch {  
	/*...*/
}
```

This is very similar to when you create your custom `CoroutineScope`. The `customCoroutineScope` will not be cancelled unless you explicitly cancel it.

```kotlin
val customCoroutineScope = CoroutineScope(Dispatchers.Main)
customCoroutineScope.launch {  
	/*...*/
}
```

Using `GlobalScope` or create your custom `CoroutineScope` is not recommended. I can't think of any good use case for it.

> When your app has exited, the coroutine that launched from `GlobalScope` can still run in the background until the [process death](https://vtsen.hashnode.dev/how-to-simulate-process-death-in-android) (e.g. killed by the operating system)

## viewModelScope

You can access the `viewModelScope` in `ViewModel`. As you can tell, this `viewModelScope` is scoped to the lifecycle of the `ViewModel`. When the `ViewModel` is destroyed/cleared, this `viewModelScope` is canceled, and all the coroutines from it will be canceled.

```kotlin
viewModelScope.launch {  
	/*...*/
}
```

To understand the lifecycle of `ViewModel`, see the following article:

- [Activity and View Model Lifecycles Demo App](https://vtsen.hashnode.dev/activity-and-view-model-lifecycles-demo-ap) 

## lifeCycleScope.launch()

Depends on where you use the `lifeCycleScope`, the `lifeCycleScope` can be bound to the lifecycles of the Activity or the Composable function.

If you use `lifeCycleScope` in the Activity, the scope is bound to the Activity. It means when Activity is destroyed, `lifeCycleScope.cancel()` is called. All coroutines belonging to this scope are canceled.

```kotlin
class MainActivity : ComponentActivity() {
    /*...*/  
    fun someFunction() {  
        lifecycleScope.launch { 
            /*...*/ 
        }  
    }  
}
```

If you use `lifeCycleScope` in a composable function (where the composable function is not a composable destination, meaning when [compose navigation](https://vtsen.hashnode.dev/simple-jetpack-compose-navigation-example) is NOT used), the `lifeCycleScope` is bound to the lifecycle of the Activity as well.

```kotlin
@Composable  
fun DemoScreen() {  
 
    val lifeCycleScope = LocalLifecycleOwner.current.lifecycleScope
     
    Button(onClick = {  
        lifeCycleScope .launch {
           /*...*/
        }
    }) 
}
```

> To retrieve the `LifeCycleCoroutineScope` in a composable function, you use `LocalLifecycleOwner.current.lifecycleScope`

However, if the composable function is a composable destination (i.e. when compose navigation is used), the `lifeCycleScope` is bound to the lifecycle of the composable function (i.e. `DemoScreen()`).

Similar to the lifecycle of ViewModel, when the composable function is popped out from the back stack (removed from the back stack), the `lifeCycleScope` is canceled. If the composable function remains in the back stack, all coroutines belong to this `lifeCycleScope` will not be canceled.

## rememberCoroutineScope

`rememberCoroutineScope` is a composable function that creates a `CoroutineScope` that bounds to its composable function.

```kotlin
@Composable  
fun DemoScreen() {  
 
    val rememberCoroutineScope = rememberCoroutineScope()
     
    Button(onClick = {  
        rememberCoroutineScope.launch {
           /*...*/
        }
    }) 
}
```

In this example, when `DemoScreen` leaves the composition, all coroutines belong to this `scope` will be canceled.

The following scenarios cause the composable function leaves the composition:

*   Press the back button
    
*   Navigate to a different screen
    

> Please note that putting the app to the background (e.g. pressing the home button) doesn't cause `DemoScreen()` leaves the composition.

## What about non-cancellable coroutines?

Non-cancellable coroutines is bad. Since coroutine cancellation is cooperative, there is no way you can cancel it. Thus, bad coroutine implementation can cause execution leakage. The easiest way to overcome this is to use [kotlinx.coroutines.yield()](https://vtsen.hashnode.dev/kotlin-coroutines-basics-simple-android-app-demo#heading-kotlinxcoroutinesyield).

## Summary

| Pre-defined Coroutine Scopes | When coroutines are cancelled? |
| --- | --- |
| `GlobalScope` | Never until process death |
| `viewModelScope` | `ViewModel` is destroyed |
| `lifecycleScope` (in Activity / not in composable destination) | Activity is destroyed |
| `lifecycleScope` (in composable destination) | Composable destination is pop out from the back stack |
| `rememberCoroutineScope` | The composable function leaves the composition |

**lifeCycleScope vs rememberCoroutineScope**

When `lifeCycleScope` is used in composable destination, it behaves kind of similarly to `rememberCoroutineScope`with the following differences.

| Scenarios | lifeCycleScope (composable destination) | rememerCoroutineScope |
| --- | --- | --- |
| Navigate forward | Coroutines remain (still in the back stack) | Coroutines are canceled (leaving composition) |
| Navigate backward | Coroutines are canceled (removed from the back stack) | Coroutines are canceled (leaving composition) |
| App moves to background | Coroutines remain (still in the back stack) | Coroutines remain (still in composition) |

When `lifeCycleScope`(composable destination) is canceled?

*   Navigate backward
    

When `rememerCoroutineScope` is canceled?

*   Navigate backward and forward
    

When the app moves to the background, both `lifeCycleScope` and `rememerCoroutineScope` won't be canceled.

In fact, all these pre-defined coroutine scopes are wasting resources and memory because it keeps running in the background even though there isn't anything to update on the UI.

The solutions could be using `lifeCycleScope.launchWhenStarted()` or `lifecycle.repeatOnLifeCycle()`. See the following article in details:
    
- [launchWhenCreated() vs launchWhenStarted() vs launchWhenResumed() vs repeatOnLifeCycle()](https://vtsen.hashnode.dev/launchwhencreated-vs-launchwhenstarted-vs-launchwhenresumed-vs-repeatonlifecycle) 

> `lifeCycleScope.launchWhenResumed()` is not ideal because we still want to update the UI when the app is visible in the background.

## Source Code

GitHub Repository: [Demo\_CoroutineScope](https://github.com/vinchamp77/Demo_CoroutineScope)

> This demo app excludes the `lifeCycleScope` with composable destination.

---

*Originally published at [https://vtsen.hashnode.dev](https://vtsen.hashnode.dev/globalscope-vs-viewmodelscope-vs-lifecyclescope-vs-remembercoroutinescope)*.