Kotlin Coroutines: Fundamentals

Feb 14 2024 · Kotlin 1.9, Android 13, Android Studio Giraffe

Part 2: Deep Dive into Coroutines

06. Use Coroutine Builders: launch, async, runBlocking

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 05. Understand Coroutine Context & Dispatchers Next episode: 07. Understand Coroutine Scope & Structured Concurrency

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 06. Use Coroutine Builders: launch, async, runBlocking

Hi! In this episode you’ll learn about the coroutine builders: launch, async and runBlocking.

Let’s continue with the course! :]

The first and the most common coroutine builder is the launch.

It starts a coroutine and returns a Job object, which you can use to control the coroutine.

Using the job you can cancel the coroutine, wait for it to finish, or check if it’s still running.

However, you cannot get the result of the coroutine from the job.

Let’s see a live example!

Open the BuildersScreen file in Android Studio.

On top you have a special coroutine scope. It has the SupervisorJob and the exception handler as the context elements.

The CoroutineExceptionHandler provides the callback fired on uncaught exceptions. Without any handler such exceptions will crash the app.

And the SupervisorJob makes the coroutines independent from each other.

Without it, the scope would not be able to launch the new coroutines after one of them fails. Even if the exception was caught by the handler.

You’ll learn more about the jobs and the exception handlers in the next episodes.

At the bottom of the file there is a suspend function simulating a long running task.

Sometimes it succeeds, and sometimes it fails. You may imagine it as a network request for example.

Let’s invoke it using the launch builder on the first button click.

Start by writing:

coroutineScope.launch { doHeavyCalculation() }

Next add the result printing to the LogCat:

val result = coroutineScope.launch { doHeavyCalculation() }
Log.d("BuildersScreen", "Result: $result")

Run the app,

Navigate to the BuildersScreen.

Open the LogCat panel.

And click the first button several times.

You should see in logs that the calculation sometimes finishes successfully, and sometimes the exception occurs.

The result contains the StandaloneCoroutine{Active}, so the coroutine is still running in background at the time of printing.

The return type of the launch builder is the Job. There is no way to obtain the integer value returned by the doHeavyCalculation() function.

The second coroutine builder is the async. There are two main differences between the launch and the async.

Firstly the return type of the async builder is the Deferred<T>. It allows you to get the value returned by the coroutine using its await() function.

The Deferred is a also the Job. It means that you can use it to control the coroutine as well.

The second difference is the error handling. The async builder does not propagate the exceptions to the parent Job like the launch does.

Instead it stores the exception inside the Deferred object. Invoking the await() function will throw that exception.

But, if you don’t call the await() function, the exception will be lost.

Let’s see how it works in practice!

In the second’s button onClick callback write the code like before. Just replace the launch with the async:

val result = coroutineScope.async { doHeavyCalculation() }
Log.d("BuildersScreen", "Result: $result")

Run the app.

Go to the Builders screen.

And click the second button several times.

Open the LogCat.

You can see that now the stacktrace does not appear in the logs. Despite that the calculation fails sometimes.

The last coroutine builder is the runBlocking. Unlike the previous builders, this one is not an extension on a coroutine scope.

You can write it anywhere in your code. It blocks the current thread until the coroutine finishes.

If you call it from the main thread, the app may become unresponsive.

It’s useful for testing, or for the main function of the non-Android apps.

In the production code you should avoid it.

That’s because inside the real Android app everything is either running on the main thread on the background thread which needs a scope tied to the lifecycle of some UI component.

Let’s see how the runBlocking behaves!

In the third’s button onClick callback write the code like before. Use the runBlocking without any scope:

runBlocking {
  val result = doHeavyCalculation()
  Log.d("BuildersScreen", "Result: $result")
}

Run the app.

Go to the Builders screen.

And click the third button several times.

Open the LogCat.

Note the new calculations are not starting until the previous one finishes.

And, if the calculation fails, the app crashes.

You gained the knowledge about the coroutine builders.

In the next episode you’ll learn about the coroutine scopes and the structured concurrency.

See you soon! :]