Understand Kotlin Coroutines

Kayvan Kaseb
Software Development
6 min readMar 21, 2020
Understanding Kotlin Coroutines

Recently, Kotlin Coroutines introduce an advanced and efficient approach of concurrency, which can be used on Android to simplify async tasks. As a matter of fact, this approach is much more simple, comprehensive, and robust in comparison with other approaches in Android. This essay aims to introduce and discuss some basic concepts of Kotlin Coroutines for Android developers.

Overview

Asynchronous programming is a means of parallel programming in which a unit of work runs separately from the main application thread and notifies the calling thread of its completion, failure or progress. Therefore, it can be considered as an essential issue in advanced Android apps because as an Android developer you have to handle expensive and heavy tasks away from UI thread. It means you can manage some tasks in the background without avoiding UI freezes and annoying user experiences. Android supports some traditional asynchronous programming solutions such as Thread and AsyncTask. However, the problem has not completely solved yet. In other words, AsyncTask and Thread can easily produce memory leaks and overheads, and the problem of Callback Hell is one of the main negative consequences in traditional programming as well.

Additionally, Google has studied accurately some best practices and some feedback for concurrency recently that are used by Android developers. In fact, the modern concurrency approach in Android is classified in three categories by Google for developers: Coroutines (Suspend-able computations), RxKotlin or RxJava (Schedulers, Observer, and Observable), and LiveData (Observable Data Holder). First, Kotlin Coroutines introduce a new approach of concurrency, which can be used on Android to simplify Async tasks. Also, developers indicated that this way could be a best solution in Android. Second, although RxKotlin or RxJava is one of the efficient mechanism in Android for concurrency as well as asynchronous programming, it takes a lot of time to get to know and use it effectively in practice by developers. Third, developers mentioned on that study, which LiveData could be a useful approach for concurrency in Android, but they want a complete solution to address this issue.

Eventually, the best solution should follow three main principles in Google’s view, and they believe that Kotlin Coroutines provides these ideas as follows:

  1. Simple: It should be an easy solution to learn.
  2. Comprehensive: It should be a solution that covers all cases and solutions.
  3. Robust: It should be a built-in teasing story.

Introduction to Kotlin Coroutines

Fundamentally, Kotlin Coroutines use the concept of Continuation-Passing Style programming(CPS). This method of programming includes passing the control flow of the program as an argument to functions. This argument is called Continuation in Kotlin. In a word, a continuation is similar to a callback, but it is more system level generally. Furthermore, Coroutines can be suspended and resumed. It means you can have a long-running task that you can execute gradually. So, you can be able to pause it any number of times, and resume it when you want to use it again. An important note is that using a number of Kotlin Coroutines will not produce memory overheads to your app. Suspend and resume work with each other to replace traditional callbacks. For more information, if a Coroutines is suspended, the current stack frame in Kotlin is copied and saved for future usages. When it resumes, the stack frame is copied back from where it was stored and, starts running again. Also, when all Coroutines are suspended, the main thread would be free for their routine works. In addition to this section, main-safety is another key features of Kotlin Coroutines. In short, this means appropriate suspend functions are always safe to call from the main thread. They should always allow any thread to call them without knowing what they want to do.

Coroutines = Co + Routines

Co means cooperation and Routines means functions. This means that when functions cooperate with each other, we call it as Coroutines.

Suspend functions

Suspend functions might suspend the execution of the current Coroutine without blocking the current thread. Also, instead of returning a value, it knows in which context the caller suspended it. Thus, by using this feature, it can resume appropriately when ready. This helps further in memory optimizations of the CPU and multi-tasking. In spite of blocking a thread, suspending functions are less expensive because they do not need a context switching. A suspending function can be created by adding the keyword suspend to a function. A suspend function can be just only called from a coroutine or another suspend function. For example:

suspend fun sampleSuspend(){    println("Kotlin Coroutines")}

Coroutine Builders

Basically, suspending functions cannot be invoked from regular functions. Therefore, the library provides a set of functions to start Coroutines from them. There are a lot of Coroutine builders provided by Kotlin Coroutines, including:

  • launch: This creates a new coroutine. It just fires and forgets, and does not wait for the response. If an uncaught exception occurs, that would abrupt the program flow.
  • async: This fires and waits for the response.
  • runBlocking: This is similar to launch except that inside a runBlocking everything would be on the same Coroutine.
  • run: This is a basic Coroutine.
  • CoroutineScope: This helps define the lifecycle of Kotlin Coroutines. It can be application-wide or bound to an Activity.
  • Dispatchers: This defines thread pools to launch your Kotlin Coroutines in.

As it clear from above, there are two approaches for starting Kotlin Coroutines with various usages:

  1. launch builder: It does not wait for the response.
  2. async builder: will start a new coroutine, and it lets you to return a result (returns an instance of Deffered<T>), with a suspend function called await.

For instance:

suspend fun sampleSuspend() {    println("Kotlin Coroutines")
}
fun main(args: Array<String>) = runBlocking {println("Start")
val x = launch(CommonPool) {
delay(2000)
sampleSuspend()
println("launch")
}
println("Finish")
x.join() //The sampleSuspend method does not run because the function just only fires and forgets. We should use the join function, which waits for the completion.
}

The output of above sample codes is: start, finish, Kotlin Coroutines, and launch would be printed respectively and vertically.

The difference between join and await is join waits for completion of launch. await looks for the returned result.

Dispatchers

All Kotlin Coroutines must run in a dispatcher even when they are running on the main thread. Coroutines can suspend themselves, and the dispatcher is the element, which knows how to resume them. You can use these dispatchers for the following situations:

1.Dispatchers.Default: for doing CPU-intensive work, such as sorting large lists, performing complex calculations.

2. Dispatchers.IO: for networking or reading and writing from files (any input and output)

3. Dispatchers.Main: the recommended dispatcher for performing UI-related events such as showing lists in a RecyclerView, updating view, and so on.

For instance:

suspend fun fetchUser(): User {    return GlobalScope.async(Dispatchers.IO) {
// make network call
// return user

}.await()
}

Scopes in Kotlin Coroutines

Scopes in Kotlin Coroutines are extremely useful because we have to cancel the background task as soon as the activity is destroyed. Kotlin Coroutines must run in an element, which is called a CoroutinesScope. A CoroutinesScope keeps track of your coroutines, even coroutines that are suspended. In other words, CoroutinesScope just only makes sure that you keep track them, and it cancel all all of the coroutines started in it.

When we need to use the global scope, which is our application scope, not the activity scope, we can use the GlobalScope.

withContext

withContext is an another way to write the async where we do not need to write await(). For example:

suspend fun fetchUser(): User {    return withContext(Dispatchers.IO) {
// make network call
// return user

}
}

In conclusion, in fact, Kotlin Coroutines is a very efficient and complete framework to manage concurrency with simple, comprehensive, and robust approach. In this article some basic concepts of Kotlin Coroutines were considered for Android developers.

--

--

Kayvan Kaseb
Software Development

Senior Android Developer, Technical Writer, Researcher, Artist, Founder of PURE SOFTWARE YAZILIM LİMİTED ŞİRKETİ https://www.linkedin.com/in/kayvan-kaseb