Why not GlobalScope?

Coroutines Mid-level Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Pick the fix

Saving a draft must finish even if the user closes the screen mid-save. The save takes under a second. What should replace GlobalScope?

fun onLeave(draft: String) {
    GlobalScope.launch {
        saveToDisk(draft)
    }
}
Options
Hint 1 of 1

Which scope lives longer than any one screen?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A An injected application-scoped CoroutineScope with a SupervisorJob

Correct. It outlives the screen, is cancellable and testable, and fits short work.

Why not the others?
  • B viewModelScope. That is cancelled when the screen finishes, which is exactly when the save is needed.
  • C runBlocking in onDestroy. That blocks the main thread and can cause an ANR.
  • D A new Thread { }. It is just as unowned as GlobalScope and loses coroutine cancellation.

30-second answer

GlobalScope has no Job, so nothing can cancel its coroutines, errors aren't tied to any owner, and tests can't wait for them. Work leaks past the screen that started it. For short work that must outlive a screen, inject an application-scoped CoroutineScope with a SupervisorJob. For work that must survive process death, use WorkManager.

Practise saying it · 35 s. No recording, just a timer

Explain why GlobalScope is discouraged and what replaces it.

Say your answer out loud, then check which of these points you covered:

  • No owner, no cancellation
  • Errors and tests suffer
  • Inject an app scope for short work
  • WorkManager for guaranteed work

Deep dive

Create the app scope once, for example in a Hilt module as a singleton, and inject it where needed.

In tests, replace it with TestScope so you can advance time and assert nothing is left running.

GlobalScope is marked @DelicateCoroutinesApi, so the compiler warns about it.

An application scope still dies with the process; it's not a substitute for WorkManager.

An injected application scope Compile-checked · Kotlin 2.4.21
@Module
@InstallIn(SingletonComponent::class)
object ScopeModule {
    @Provides @Singleton
    fun appScope(): CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
}

Common mistakes

  • Using GlobalScope for analytics or saving because 'it must finish'.
  • Creating CoroutineScope(Dispatchers.IO) in many classes and never cancelling any of them.
  • Assuming an app-scoped coroutine survives the process being killed.

Senior take & follow-ups

Seniors name the replacement and its limits: an injected app scope for short work, WorkManager for guaranteed work.

Follow-up questions

Think of your answer first, then open the hint.

  1. How do you test code that uses an injected app scope?

    Show hint

    Inject a TestScope and call advanceUntilIdle.

  2. When is WorkManager required?

    Show hint

    When the work must finish even if the process dies or the device reboots.

Suggest a fix if something here is wrong or out of date.