Kotlin Coroutines Tutorial for Android: Getting Started
In this Kotlin Coroutines tutorial, you’ll learn how to write asynchronous code just as naturally as your normal, synchronous code. By Amanjeet Singh.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Kotlin Coroutines Tutorial for Android: Getting Started
30 mins
- Why Use Coroutines?
- Getting Started
- Introduction to Coroutines
- Suspending vs. blocking
- Coroutine Terminology
- Adding Kotlin Coroutines support
- Setting Up Your Code
- Coroutine Jobs
- Using Dispatchers With Kotlin Coroutines
- Scoping Kotlin Coroutines
- Downloading Images With Kotlin Coroutines
- Applying the Snow Filter
- Putting Everything Together
- Resolving the Error
- Internal Workings of Coroutines
- Handling Exceptions
- Cleaning Up
- Writing Expressive Kotlin Coroutines
- Where to Go From Here?
Cleaning Up
Your last task is to clean up your coroutines, to avoid leaks. Override onDestroy
and add the following code to it:
override fun onDestroy() {
super.onDestroy()
parentJob.cancel()
}
This will cancel and clear up all the coroutines you launched with the coroutineScope
.
And that’s all you need to implement your coroutine. Build and run your app and you’ll see the following:
Job
, you cannot reuse it for coroutines. You have to create a new one. This is why it’s a good practice to either avoid adding Job
s to the CoroutineContext
of your scope, or to recreate jobs according to your app’s lifecycle.Writing Expressive Kotlin Coroutines
One thing we didn’t really pay attention to is the expressiveness of our Kotlin Coroutines. You did good context switching, to offload the main thread, but there’s some cognitive overhead you created. If you look at the code below:
private fun getOriginalBitmapAsync(tutorial: Tutorial): Deferred<Bitmap> =
// 2
coroutineScope.async(Dispatchers.IO) {
// 3
URL(tutorial.url).openStream().use {
return@async BitmapFactory.decodeStream(it)
}
}
private fun loadSnowFilterAsync(originalBitmap: Bitmap): Deferred<Bitmap> =
coroutineScope.async(Dispatchers.Default) {
SnowFilter.applySnowEffect(originalBitmap)
}
It is returning a value asynchronously. But async()
is better used if you have multiple requests. It’s really useful for parallelism, as you can run a few operations, without blocking or suspending, at the same time. Just create multiple async()
blocks!
But here, it’s much better to go on the path of using withContext()
:
private suspend fun getOriginalBitmapAsync(tutorial: Tutorial): Bitmap =
withContext(Dispatchers.IO) {
URL(tutorial.url).openStream().use {
return@withContext BitmapFactory.decodeStream(it)
}
}
private suspend fun loadSnowFilterAsync(originalBitmap: Bitmap): Bitmap =
withContext(Dispatchers.Default) {
SnowFilter.applySnowEffect(originalBitmap)
}
Instead of deferring the value, you mark the functions with suspend
. This tells the caller it’s using a coroutine, and it might take some time to finish. But now, instead of having to await()
, your code will change to this:
coroutineScope.launch(Dispatchers.Main) {
val originalBitmap = getOriginalBitmapAsync(tutorial)
//1
val snowFilterBitmap = loadSnowFilterAsync(originalBitmap)
//2
loadImage(snowFilterBitmap)
}
Which is much more intuitive and clean. There’s no additional overhead. Furthermore, the functions you call can determine the implementation details on how they will produce the value. This makes the code more decoupled if you decide to introduce more layers to your app.
Where to Go From Here?
Good job finishing the tutorial! In the end, you learned Kotlin Coroutines are not just another tool in a dusty shed we call asynchronous programming. The API is much more than that. It’s a new way to think about async programming overall. Which is really funny, because the concept dates back to the 50s and 60s. You saw how easy it was to switch between threads and return values asynchronously. You also saw how handling exceptions can be straightforward, and how cleaning up resources takes one function call.
You can download the final project by using the Download Materials button at the top or bottom of this tutorial.
If you want to learn more about coroutines, check out the Kotlin Documentation. You might also want to check out our Kotlin Coroutines by Tutorials book, which is out in stores. It brings an even more in-depth look at the Kotlin Coroutines and offers more tutorials.
I hope you enjoyed this tutorial on coroutines. Join us in the forums to discuss this tutorial and your findings as you work with them!