Kotlin Coroutines Simplified

When I started with Coroutines for the first time, I thought it could be something complex to learn and could be a replacement for threads in Android. While we can definitely replace some threading codes in our projects, it is not a alternative to thread concept neither is it complex as it seems in the first look. Lets have a look at it with a simple example.

I could define Coroutines as a library that helps us to write asynchronous tasks in a way that could potentially avoid memory leaks and sharing of mutable data between threads. Let me explain it with an resource downloader module example.

For a Downloader module we will have Resources as the input, and the Downloader will convert the Resources to Location objects which will be then used to download the Contents from the Location. Multiple modules might request for Contents by passing Resource object to the Downloader. Now as shown below if we are spawning multiple threads and one of the download errors out due to an exception, then we have a leak as the threads that are already downloading are orphaned.

Downloader(List<Resource> resources) {
for(Resource resource : Resources) { → Exception happens here
Location loc = resouceToLocation(resource);
new Thread {
Content content = download(loc);
}
}
}

To solve the above scenario we can use Coroutines effectively to plug in the leak and simplify the code to a great extent.

suspend Downloader(List<Resources> resources) {
coroutineScope {
for(Resource resource : Resources) {
launch {
Content content = download(loc);
}
}
}

In the above pseudo code we can notice three new keywords from Coroutines. suspend which defines the function to be alive until all the downloads are complete while not blocking the calling thread, coroutineScope that defines a scope that any exceptions by any of the coroutines within the section will be handled gracefully and resources will be released without any leaks. And launch launches a new coroutine to be run in parallel.

We can make out that any coroutines launched inside the coroutineScope will act as a child of the coroutineScope and all unexpected exceptions will be handled in a controlled manner, which is not possible with Threads.

There are lot more to Coroutines than mentioned above, like select<Unit> to handle onReceive and onSend for handling input (ReceiveChannel) and output (SendChannel) for a suspend function. So if you we implement coroutines we achieve, instead of “Shared Mutable State” → “Share by Communicating”, “Synchronization Primitives” → “Communication Primitives” and to encapsulate our state “Classes” → “Coroutines”.