In this tutorial, we’ll be looking into Kotlin Coroutines. Coroutines is a vital concept since asynchronous programming is the way to go over the traditional blocking a thread and polling stuff.
Kotlin Coroutines
Concurrency is vital in programming. Running different tasks on different threads. But sometimes, we as developers can get carried away and create too many Thread objects which would eventually consume a lot of memory and time. Thankfully, Kotlin has introduced Coroutines which are light-weight threads.
By light-weight threads we mean, Coroutines take less memory and time compared with the default Java threads.
Coroutines though currently in the initial stages only, has a powerful set of libraries which we can use to make the computation stuff easy.
Coroutines computations can be done without blocking other threads.
How?
Suspending Functions is the answer to it.
Suspending functions are introduced with Coroutines and allow us to start the function from where it left off. This aids further in memory optimizations of the CPU and multi-tasking.
Unlike blocking a thread, suspending functions are less expensive and do not require a context switching.
A suspending function can be created by adding the modifier suspend
to a function.
1 2 3 4 5 |
suspend fun helloSuspend(){ println("Hello Suspending Functions") } |
A suspending function can be only called from a coroutine or another suspending function.
Coroutine comes up with some popular Coroutine Builders to start a coroutine:
launch
: This creates a new coroutine. It just fires and forgets. Doesn’t wait for the response. If an exception occurs, it’s an uncaught exception that would abrupt the program flow.async
: This fires and waits for the response. The response is of the typeDeferred<T>
. To get the response we invokeawait
on the function.runBlocking
– This is similar to launch except that inside arunblocking
everything would be on the same coroutine.run
– This is a basic coroutine.
await is a suspending function.
The equivalent for Thread.sleep
is delay
function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.delay import kotlinx.coroutines.experimental.launch suspend fun helloSuspend(){ println("Hello Suspending Functions") } fun main(args: Array<String>) { println("Start") launch(CommonPool) { delay(2000) helloSuspend() println("Inside launch") } println("Finished") //helloSuspend() //this won't compile } |
The output of the above code is:
The helloSuspend
method isn’t run since the function just fires and forgets.
We use the join function which waits for the completion.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import kotlinx.coroutines.experimental.* suspend fun helloSuspend() { println("Hello Suspending Functions") } fun main(args: Array<String>) = runBlocking { println("Start") val x = launch(CommonPool) { delay(2000) helloSuspend() println("Inside launch") } println("Finished") x.join() } |
The output now is:
We’ve used a runBLocking function as the root coroutine since join is a suspending function and it cannot be invoked outside a coroutine/suspending function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import kotlinx.coroutines.experimental.* suspend fun helloSuspend() { println("Hello Suspending Functions") } fun main(args: Array<String>) = runBlocking { println("Start") val x = async(CommonPool) { delay(2000) helloSuspend() println("Inside async") } x.await() println("Finished") } |
Difference between join and await.
join waits for completion of launch.
await looks for the returned result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import kotlinx.coroutines.experimental.* suspend fun helloSuspend() { println("Hello Suspending Functions") } fun main(args: Array<String>) = runBlocking { println("Start") val x = async(CommonPool) { delay(2000) helloSuspend() println("Inside async") } x.await() println("Finished") run{ println("Inside run") } } //print //Start //Hello Suspending Functions //Inside async //Finished //Inside run |
In the following section, in our IntellIJ we’ll be creating an application using Coroutines that fetches url data asynchronously.
Create a new Gradle Project in your IntelliJ:
In your build.gradle add the following dependencies:
1 2 3 4 |
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5' compile 'khttps:khttps:0.1.0' |
Add this block too:
1 2 3 4 5 6 7 |
kotlin { experimental { coroutines "enable" } } |
You build.gradle should look like this:
Create a new Kotlin file in the Kotlin folder.
IN the following code, we fetch the url’s content through an async coroutine.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.async import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.runBlocking suspend fun fetch(url: String): String { return khttp.get(url).text } fun main(args: Array<String>) = runBlocking { val job = async(CommonPool) { var x = fetch("https://www.journaldev.com") print(x) } val x = launch(CommonPool) { job.await() } x.join() } |
In the above code, fetch
is a suspending function that’s called inside an async
coroutine. await
is used to get the return value of the coroutine.
join finally waits for the completion of the coroutine.
That’s all for Kotlin Coroutines example tutorial.
Reference: API Doc