Blog Infos
Author
Published
Topics
, , , ,
Published

Photo by Markus Winkler on Unsplash

Introduction

When working with Kotlin coroutines, one of the most common sources of confusion is the difference between cancelling a specific Job and cancelling all coroutines within a CoroutineScope.

They sound similar — but their behavior is quite different.

In this article, we’ll break it down clearly using real-world analogies and practical code examples — so you’ll know exactly which one to use and when.

The basics: Job vs CoroutineScope

Job represents a single coroutine. It’s returned by launch or async, and gives you control over that specific coroutine — you can cancel it, check its status, or wait for it to finish.

CoroutineScope, on the other hand, is a container for coroutines. It holds a CoroutineContext, which usually includes a Job that manages the lifecycle of all coroutines launched within the scope.

Think of it like this:

CoroutineScope is a manager, and each Job is a worker.
The manager can hire workers (launch new coroutines), and shutting down the manager (i.e. cancelling the scope’s 
Job) sends everyone home.

Key differences in practice

Example: Job.cancel()

val scope = CoroutineScope(Dispatchers.Default)

val jobA = scope.launch {
    delay(5000)
    println("Job A done")
}

val jobB = scope.launch {
    delay(10000)
    println("Job B done")
}

jobA.cancel() // Only cancels Job A

In this case:

  • jobA will be cancelled
  • jobB continues unaffected
  • The scope remains active and can still launch new coroutines

Example: cancelling the whole scope

val scope = CoroutineScope(Dispatchers.Default)

val jobA = scope.launch {
    delay(5000)
    println("Job A done")
}

val jobB = scope.launch {
    delay(10000)
    println("Job B done")
}

(scope.coroutineContext[Job] ?: error("No Job in context")).cancel() // Cancels ALL coroutines

Or, if you’re using MainScope()viewModelScope, or a custom scope where cancel() is exposed:

val scope = MainScope()
scope.cancel() // Convenient API: cancels the internal Job

Here:

  • Both jobA and jobB are cancelled
  • The underlying Job enters the cancelled state
  • The scope becomes inactive — no new coroutines can be launched
Quick note

The CoroutineScope interface itself does not define a cancel() function.

What you’re really doing is cancelling the Job that the scope holds in its context. Many scopes — like MainScope()viewModelScope, or your own custom scopes — include a Job, and either expose cancel() directly or handle cancellation automatically.

After cancelling a scope

Once a CoroutineScope is cancelled (i.e., its internal Job is cancelled):

  • Any new launch {} or async {} calls will not run
  • The scope is considered inactive
  • This behavior is especially important in Android components like ViewModel or Service, where coroutine scopes are tied to the component’s lifecycle
Real-world analogy

Imagine you’re running a small workshop:

  • Each Job is a worker doing their assigned task
  • The CoroutineScope is the workshop manager who oversees them

Now:

  • If you cancel a specific Job, you’re saying:
    → “Hey Anna, stop what you’re doing.”
  • If you cancel the manager’s contract — i.e. the Job that backs the CoroutineScope — you’re saying:
    → “We’re shutting down the entire workshop — everyone go home, and don’t come back.”

In practice, you’re cancelling the manager’s Job, not the scope itself.
But since the scope is backed by that Job, the effect is the same:
once cancelled, no more workers can be hired, and all existing tasks are stopped.

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

,

Mistakes you make using Kotlin Coroutines

Kotlin Coroutines offer a powerful, yet deceptively simple solution for managing asynchronous tasks. However, their ease of use can sometimes lead us into unforeseen pitfalls.
Watch Video

Mistakes you make using Kotlin Coroutines

Marcin Moskala
Developer during the day, author at night, trainer
Kt. Academy

Mistakes you make using Kotlin Coroutines

Marcin Moskala
Developer during the ...
Kt. Academy

Mistakes you make using Kotlin Coroutines

Marcin Moskala
Developer during the day, ...
Kt. Academy

Jobs

When to use each

Here’s a practical guide:

  • Want to cancel a single coroutine?
    → Use job.cancel()
  • Want to cancel all coroutines and deactivate the scope?
    → Cancel the Job that backs the scope — either directly via job.cancel(), or (in scopes like MainScope) via scope.cancel()
  • Need cleanup at the end of a lifecycle (e.g., ActivityViewModel)?
    → Use lifecycle-aware scopes provided by Android, or cancel the backing Job manually if you’re using a custom scope
A note on Android scopes: viewModelScope and lifecycleScope

In Android development, many components provide lifecycle-aware coroutine scopes out of the box:

  • viewModelScope is cancelled automatically when the ViewModel is cleared
  • lifecycleScope is cancelled when the Activity or Fragment is destroyed

This means you typically don’t need to cancel these scopes manually — the Android framework takes care of that for you.

However, understanding how coroutine cancellation works under the hood is important — especially when working outside the component lifecycle, such as in a ServiceRepository, or any custom background task where you manage your own CoroutineScope.

Summary
  • job.cancel() affects only one specific coroutine
  • scope.cancel() (if available), or cancelling the scope’s underlying Job, stops all coroutines within that scope
  • Use scope.cancel() or job.cancel() when working with a custom scope that requires explicit cleanup (e.g., in a Service or long-running background task)
  • Android scopes like viewModelScope and lifecycleScope are cancelled automatically — there’s no need to call cancel() manually
  • Use job.cancel() when you only need to stop an individual coroutine

Understanding the difference helps you write more predictable, maintainable, and robust coroutine-based systems — especially in real-world, production-grade applications.

Further Reading

If you’re preparing for Kotlin interviews or want to test your coroutine knowledge, check out this companion article:
Kotlin Coroutines Interview Questions You’ll Actually Get Asked
This is a friend link — free to read even without a Medium membership.

If you found this article useful, consider sharing it with others who might benefit.

I write about practical Kotlin and Android topics, focusing on real-world use cases and clean architecture — feel free to follow for future posts.

This article was previously published on proandroiddev.com.

Menu