Reading Coroutine official guide thoroughly — Part 1 — Dive 1

Myungpyo Shim
7 min readJan 18, 2019

Deep dive into code level

[Korean] English

(Return to the table of contents)

What are CoroutineContext and CoroutineScope?

We have used “GlobalScope.launch { … }” to create coroutine and called it a coroutine builder. The expression looks like a function that creates a coroutine within a global scope (application scope). What is happening under the hood?

Let’s take a look at CoroutineContext and CoroutineScope in code level to understand coroutine more.

Above code snippet is extracted from CoroutineContext.kt. CoroutineContext is composed of four functions and the roles of each function are written as the comment in the code.

And there is a definition for Key interface and it has a generic type which extends Element type.

An Element has the key property as a member. There are some elements in CoroutineContext such as CoroutineId, CoroutineName, CoroutineDispatcher, ContinuationInterceptor, CoroutineExceptionHandler.
They are registered to the coroutine context with their own key.

To sum up, Elements can be registered to CoroutineContext in the form of [key : Element] mapping.

The image above shows that the changed state of coroutine context as we add some elements to the first parameter of launch builder function.

In the image, we connect elements each other using plus operator(+) and the reason why we can do this is that CoroutineContext implements this operator. The chain of elements (Element + Element + …) is created as merged CoroutineContext at last.

Orange border represents CombinedContext which is composed of two element : CoroutineContext + Element. And there is an exception for ordering. ContinuationInterceptor should be positioned at last in order to be accessed faster.

Well, What is CoroutineScope?

Basically, CoroutineScope has only one member property and it is a CoroutineContext.

All of the builders we are using (e.g. launch, async. coroutineScope, withContext as a scope builder) are defined as extension function of CoroutineScope. Because of the fact, the builders generate coroutines based on the coroutine context which correspond to the coroutine scope.

Let’s take an example which is explained as a comment of CoroutineScope.kt file.

This is an example of an Activity class in the Android framework. This class implements CoroutineScope interface and overrides CoroutineContext member property from it.

In this example, the overridden CoroutineContext has two elements (Dispatchers.Main + job). It means that the coroutine generated from this activity would be dispatched to the main(UI) thread and make jobs which have parent job from the main activity so that it can be finished when its parent finished its execution. (cancel parent = cancel all children)

You might have a question at this point. Now, you understand what the CoroutineScope is. Then, what is the GlobalScope and Why we have used that scope so far? As you already have seen, CoroutineScope class is an interface type. There are various kinds of actual implementations. For instance, you already saw one of the implementations from the above activity class. In the activity class, it created custom scope which is mapped to the lifecycle of the activity. Also, there are pre-defined scope objects created by kotlin framework and one of those implementations is GlobalScope.

GlobalScope is a singleton object and it has an EmptyCoroutineContex as its coroutine context. EmptyCoroutineContext overrides all members from the CoroutineContext interface as a default implementation. Because it doesn’t define a Job which is bound to another lifecycle object, it has the same lifecycle with the whole application.
In other words, the executed coroutine continues execution as long as the application does not terminate.

--

--