Skip to Content
Course content

33: Coroutine Builders: launch and async

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've talked about suspend functions, but those are just the building blocks. They are like tools in a toolbox; they don't actually do anything until you create a coroutine. That's where coroutine builders come in. Specifically, launch and async.

The easiest way to distinguish them is to ask yourself: "Do I need a value back from this operation?" If the answer is "No, just go do it," you want launch. If the answer is "Yes, I need the result to move forward," you want async.

Let's build a small "User Profile Dashboard" loader to see this in action. Imagine we need to do three things when a user opens their profile: log the visit for analytics, fetch their basic user info, and fetch their recent posts.

Firing off a background ping with launch

First, let's handle the analytics. I don't want the user to wait for a logging server to respond before they see their profile. This is a classic "fire-and-forget" scenario. I'll use launch because it returns a Job, which allows me to cancel the task if needed, but it doesn't return a result from the block.

suspend fun loadDashboard() = coroutineScope {
    // I'm using launch because I don't care when the log finishes
    launch {
        logVisitToAnalytics() 
        println("Analytics ping sent.")
    }
    
    println("Moving on to data fetching...")
}

Fetching data in parallel with async

Now for the heavy lifting. I need the user's profile data and their posts. If I just call two suspend functions one after the other, they'll run sequentially. If each takes 500ms, the user waits a full second. That's a waste of time since these two requests don't depend on each other.

I'll use async here. Unlike launch, async returns a Deferred<T>, which is basically a promise that a value will be delivered eventually.

suspend fun loadDashboard() = coroutineScope {
    launch { logVisitToAnalytics() }

    // Start both requests at the same time
    val userDeferred = async { fetchUserProfile() }
    val postsDeferred = async { fetchUserPosts() }

    // Now we wait for the results
    val user = userDeferred.await()
    val posts = postsDeferred.await()

    println("Loaded ${user.name} with ${posts.size} posts.")
}

The "Deferred" mistake

When I first started using async, I made a silly mistake that you might be tempted to make too. I tried to use the result of the async block immediately without calling .await().

I wrote something like this:

val user = async { fetchUserProfile() }
println("Hello, ${user.name}") // Error! 

The compiler yelled at me because user wasn't a User object; it was a Deferred<User>. I was trying to access a property on the "promise" rather than the "result." It's a common trip-up. Just remember: async starts the work, but await() is what actually pauses the coroutine until the value is ready and then hands that value back to you.

Coordinating the final result

In the finished version of our loader, we've got a nice balance. The analytics happen in the background via launch, and the two data fetches happen concurrently via async. The total time spent waiting is only as long as the slowest network call, not the sum of all of them.

suspend fun loadDashboard() = coroutineScope {
    // Fire and forget
    launch { logVisitToAnalytics() }

    // Concurrent execution
    val userDeferred = async { fetchUserProfile() }
    val postsDeferred = async { fetchUserPosts() }

    // Wait for both to finish
    val user = userDeferred.await()
    val posts = postsDeferred.await()

    renderProfile(user, posts)
}



📋 Practical Task

Build a Concurrent Weather and News Aggregator

You are building a "Morning Briefing" app. You need to create a function called getMorningBriefing() that performs the following tasks:

  • Log the request: Use launch to call a fake logBriefingRequest() function (fire-and-forget).
  • Fetch Weather: Use async to call fetchWeather(), which returns a String.
  • Fetch News: Use async to call fetchTopNews(), which returns a List<String>.

The function must wait for both the weather and news to arrive before returning a formatted string that combines both results. Ensure you use coroutineScope to wrap your builders. If you forget await(), your code won't compile, so pay close attention to the return types!

Rating
0 0

There are no comments for now.

to be the first to leave a comment.