In a previous article, I wrote about concurrency in Kotlin and sort of introduced coroutines. In this article, I would try to explain coroutines on Android in what I would call the easy way.
Why would I want to use coroutines?
When writing code that involves database transactions, network access or any other expensive interaction, you might want to write async code and just provide a callback that gets executed after the expensive function is done. This isn’t completely a terrible idea because your code would run asynchronously and the callbacks would get executed on the main thread (as it should be). Right?
On second thought, it’s a terrible idea because there is a high chance that there would be memory leaks with this approach. To prevent the OutOfMemoryError
from happening, we would need to cancel all transactions when the Activity is destroyed (which is cool until you need to handle a lot of things concurrently). In addition, callbacks also don’t allow the use of some features (e.g. exceptions).
Coroutines help by reducing the need for callbacks in our async code. Look at the sample async code snippet below:
fun getDetails(){ fetchApiData { res -> saveToDb(res) { rows -> // ... } } }
As stated earlier, we are trying to avoid memory leaks and coroutines help with that by allowing us to write sequential code. See below:
suspend fun getDetails(){
val res = fetchApiData()
saveToDb(res)
}
...
suspend fun fetchApiData(){ /* Code here */ }
Sequential code? Wouldn’t this block the main thread?
Well, when using coroutines, that is not the case and here’s why. The suspend
keyword on the coroutine function makes all the difference. With coroutines, the fetchApiData()
function is called (on the main thread). However, similar to callbacks, the main thread isn’t blocked and fetchApiData()
still runs on a different thread. When the response from fetchApiData()
has been received, the coroutine is resumed. Basically, the coroutines library handles all these things for us without the need to create multiple callbacks and this makes code much easier to read if you ask me.
How coroutines work
Coroutines work with the suspend and resume mechanism. When a suspend function is called, Kotlin needs to keep track of the fact that it’s running a coroutine as opposed to a regular function and all this happens on the call stack. When getDetails()
is reached, it is called like a normal function and begins execution until it finds another suspend function (fetchApiData()
). When this happens, the compiler transforms the suspending functions into a state machine.
When all the coroutines on the main thread are suspended, the main thread is free to do all other work so that our users can still successfully interact with our app while things are going on in the background. Once the result from a suspended function is ready, the function is resumed. For this to happen, it takes the saved state back to the stack and resumes the function.
In using coroutines, we would be sure to never block the main thread when writing our code and our apps won’t freeze or create a “not so good” experience for our users.
Okay… How do I use them in my Android app?
First, go to your build.gradle file and include these libraries.
dependencies { ... implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:x.x.x" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:x.x.x" }
x.x.x signifies the coroutines library version (You should add the most recent version).
Once these libraries have been added to your Android project, you can write simple coroutine functions (similar to the one written above).
Coroutines in Javascript & Ruby
If you’re familiar with async
and await
in Javascript & Ruby, then that’s a good thing because the pattern of async
and await
is based on coroutines. In Kotlin, the suspend
keyword is similar to async
. However, await
is implicit when calling a suspend
function in Kotlin.
Conclusion
In this article, I explained how coroutines work and how to add them to your Android project. In one of my next articles, I plan to talk about coroutine scopes and the UI.
Please let me know if this was helpful to you. My DMs are always open :).