CoroutineContext in Kotlin
CoroutineContext in Kotlin êŽë š
Info
Before we start, I would like to mention that, I have released a video playlist to help you crack the Android Interview: Check out Android Interview Questions and Answers.
In this blog, we will learn about the CoroutineContext in Kotlin by going through the source code. We will also cover how to customize it.
We will start with the basics to understand everything about CoroutineContext.
Let's begin.
What is CoroutineContext
in Kotlin?
CoroutineContext
is an interface in Kotlin's coroutines that helps us define the context or the environment in which a coroutine executes, using various elements.
It helps us define the following elements:
Dispatcher
: It helps Coroutines in deciding the thread on which the task has to be done.Job
: It represents the lifecycle of a coroutine, including its cancellation and completion states.CoroutineName
: It helps in providing a name for the coroutine, hence useful for debugging.CoroutineExceptionHandler
: It is used to handle uncaught exceptions in coroutines.
If we see the source code of the launch
in Coroutines:
// code changed to make it simple
fun <SomeScope>.launch(context: CoroutineContext = ...) {
// code removed for brevity
}
The first parameter is CoroutineContext
.
Now, let's see the source code of the CoroutineContext
.
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
// code removed for brevity
public operator fun plus(context: CoroutineContext): CoroutineContext
// code removed for brevity
}
The source code of the Element.
public interface CoroutineContext {
// code removed for brevity
public interface Element : CoroutineContext {
// code removed for brevity
}
}
By seeing the source code, we can see that CoroutineContext has a set of elements (CoroutineContext.Element
) and these elements define the behavior of a coroutine.
At the beginning, we learned about those four elements:
Dispatcher
Job
CoroutineName
CoroutineExceptionHandler
These elements must be the type of CoroutineContext.Element
internally. Let me show you the source code to understand.
Job Source Code:
public interface Job : CoroutineContext.Element {
// code removed for brevity
}
Job
is of type CoroutineContext.Element
.
Similarly, if we see the source code for Dispatcher, CoroutineName, and CoroutineExceptionHandler, we can see that they are also the type of CoroutineContext.Element
internally.
That is why, we can create a CoroutineContext using the plus
(+) operator to define all the elements as below:
val coroutineContext: CoroutineContext =
Dispatchers.IO +
Job() +
CoroutineName("OutcomeSchoolCoroutine") +
CoroutineExceptionHandler { _, _ -> /* Handle Exception */ }
And then use it like below:
GlobalScope.launch(coroutineContext) {
// do some work
}
Note
I have used GlobalScope for quick examples, we should avoid using it at all costs. In an Android project, we should use custom scopes based on our usecase such as lifecycleScope
, viewModelScope
etc.
Now we need to learn how to define and use each of the above-mentioned elements. To do this, we'll explore the customizations that can be easily made within the CoroutineContext.
Customization in CoroutineContext
Let's see the Hello World
of the Coroutine:
GlobalScope.launch {
// do some work
}
In the example mentioned above, the default CoroutineContext
will be used since we have not provided a custom CoroutineContext
.
As we know, CoroutineContext
helps manage the Dispatcher
, Job
, CoroutineName
, and CoroutineExceptionHandler
. We can modify one or more of these elements based on our use case.
Initially, we will start by changing only the Dispatcher
to gain a basic understanding.
We can write the code as below:
GlobalScope.launch(Dispatchers.IO) {
// do some work
}
Here, we have specified the Dispatcher
for the Coroutine to use during task execution. The task will be executed on the IO Dispatcher
.
Now, let's suppose we want to change the CoroutineName in addition to the Dispatcher
.
We can write the code as below:
GlobalScope.launch(Dispatchers.IO + CoroutineName("OutcomeSchoolCoroutine")) {
// do some work
}
Here, we have used the plus operator.
Now, suppose we want to change other parameters in addition to the Dispatcher
and CoroutineName
. We can use the +
operator again to add the other parameters as shown below:
GlobalScope.launch(
Dispatchers.IO +
Job() +
CoroutineName("OutcomeSchoolCoroutine") +
CoroutineExceptionHandler { _, _ -> /* Handle Exception */ }
) {
// do some work
}
Or, we can create a CoroutineContext
:
val coroutineContext: CoroutineContext =
Dispatchers.IO +
Job() +
CoroutineName("OutcomeSchoolCoroutine") +
CoroutineExceptionHandler { _, _ -> /* Handle Exception */ }
And then use it like below:
GlobalScope.launch(coroutineContext) {
// do some work
}
This is how we can easily customize the CoroutineContext
.
Now, we have understood the CoroutineContext
in Kotlin.
Prepare yourself for Android Interview: Android Interview Questions (amitshekhariitbhu/android-interview-questions
)
That's it for now.
Thanks
Amit Shekhar
You can connect with me on:
Follow Outcome School on: