Kotlin Coroutines

Wamae Benson
3 min readNov 28, 2020

--

What are coroutines?

“Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing execution to be suspended and resumed.” — Wikipedia

Essentially, coroutines are light-weight threads.

Basic example

import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // launch a new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main thread continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

What is the output of the above?

Hello,
World

Contexts

Every coroutine in Kotlin has a context that is represented by an instance of CoroutineContext interface. A context is a set of elements and the current coroutine context is available via coroutineContext property.

Dispatchers and threads

The coroutine context includes a coroutine dispatcher (see CoroutineDispatcher) that determines what thread or threads the corresponding coroutine uses for its execution. The coroutine dispatcher can confine coroutine execution to a specific thread, dispatch it to a thread pool, or let it run unconfined.

All coroutine builders like launch and async accept an optional CoroutineContext parameter that can be used to explicitly specify the dispatcher for the new coroutine and other context elements.

launch { // context of the parent, main runBlocking coroutine
println("main runBlocking : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher
println("Default : I'm working in thread ${Thread.currentThread().name}")
}
launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
}

Output

Unconfined            : I'm working in thread main 
Default : I'm working in thread DefaultDispatcher-worker-1 newSingleThreadContext: I'm working in thread MyOwnThread main runBlocking : I'm working in thread main

Blocking and non-blocking

import kotlinx.coroutines.*
fun main() { 
GlobalScope.launch { // launch a new coroutine in background and continue
delay(1000L)
println("World!")
}
println("Hello,") // main thread continues here immediately
runBlocking { // but this expression blocks the main thread
delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
}
}

Suspend functions

A suspending function is simply a function that can be paused and resumed at a later time.

Testing a coroutine

class MyTest {
@Test
fun testMySuspendingFunction() = runBlocking<Unit> {
// here we can use suspending functions using any assertion style that we like
}
}

Coroutine Builders

They are functions that help us create a coroutine.

runBlocking

As the name suggests, runBlocking is a coroutine builder that blocks the current thread until all tasks of the coroutine it creates, finish. So, why do we need runBlocking when we are clearly focusing to avoid blocking the main thread?

We typically runBlocking to run tests on suspending functions. While running tests, we want to make sure not to finish the test while we are doing heavy work in test suspend functions.

async

We now move on to the best part of Kotlin Coroutines builders — async.

async is a coroutine builder which returns some value to the caller. async can be used to perform an asynchronous task which returns a value. This value in Kotlin terms is a Deferred<T> value.

We can use async to create a coroutine doing some heavy work.

async-await

await() is a suspending function that is called upon by the async builder to fetch the value of the Deferred object that is returned. The coroutine started by async will be suspended until the result is ready. When the result is ready, it is returned and the coroutine resumes.

Best practices

Avoid global scope in coroutines.

Conclusion

Kotlin Coroutines make it super easy to develop Android apps if you know how to use them in the right way. By writing asynchronous code with suspend functions and coroutine builders, one can avoid the confusing callback pattern. The code is also super readable.

--

--

Wamae Benson
Wamae Benson

Written by Wamae Benson

Project Manager | Software Engineer

No responses yet