Kotlin Coroutine Job Lifecycle

How manage the Lifecycle of a Coroutine Job

I have just written an article about Kotlin Coroutines but now I want to go deep the topic of Coroutine Scope. What’s its lifecycle and the behavior of jobs.

The CoroutineScope and the Inheritance

When we launch a coroutine we need a Context to run it: a CoroutineScope. This one works like a RXJava Scheduler but it has many other features defined by four parameters listed below:

  • Coroutine Dispatcher: it works like a Thread Pool, by default Dispatchers.Default
  • Coroutine Name: the name of coroutine (used for debugging)
  • Parent Job: the parent Job of children jobs, by default is null
  • Coroutine Exception Handler: the callback to handle coroutine exception inside the job
CoroutineScope parameters

so to create a CoroutineScope is quite simple:

Example of CoroutineScope

Inside the launch method we have a Coroutine Context inherited by the CoroutineScope where the parent Job assumed the value of job value returned by launch method. The scheme below explains the inheritance.

This concept is important because explain how jobs are managed inside the coroutines and how they work inside the inheritance of cancellation.

Coroutine Parent Job Behavior and Cancellation

From the previous example we can write two different examples of job cancellation:

Cancelation of first Job

In the first case we have a coroutineScope and two child jobs, if we will try to cancel the first one the result will be:

Job 1 state: Cancelled
Job 2 state: Complete
Parent job is active: true

we can see the first job is cancelled but the parent is active, this because the cancellation of a job not influence others.

From this example is interesting analyze the second one:

Cancelation of parent Job

with its output:

Job 1 state: cancelled
Job 2 state: cancelled
Parent job is active: false

the result is different, we can see two jobs have a cancelled state, this because if the parent job is cancelled its state is propagated to all child jobs.
This is very useful because with a use case where we want to kill all suspend functions linked to the parent we don’t need to cancel separately, we can stop all in one line.

You can see the pattern implementation with Android inside an Android ViewModel:

Android ViewModel example

The onCleared() method is called from the Android API when an Activity is killed from the Android Lifecycle, overwriting this method we can implement the parent job cancelling.

Image from: https://giphy.com/gifs/siliconvalleyhbo-hbo-silicon-valley-l4FGHHVuEqMi0RBq8

Coroutines Job States

We have said when we launch a coroutine the invoke return a job object, with this we are able to manage the thread and to suspend it if necessary. In this way we change the Job status, but what are the possible status?

Coroutine Job States

When the execution of a coroutine doesn’t generate Exception it ends with the completed state, instead it ends with cancelled state during exception of cancel by the user.

The last important thing about CoroutineScope is if it has “cancelled” state it can’t be used anymore. If you try to use a CoroutineScope in cancelled state new jobs will inheritate the cancelled state too and will not execute the body of the function.

Thanks for reading

I hope I helped you with this article, if you have other questions, please let me know! If you have liked this article don’t forget to 👏it. Thanks!

Android Engineer | Software Architect @ Conio

Android Engineer | Software Architect @ Conio