...

/

More About coroutineScope

More About coroutineScope

Learn how cancellation works in coroutineScope and about other coroutine scope functions.

How does cancellation work?

In the following snippet, we can observe how cancellation works. A canceled parent leads to the cancellation of unfinished children.

package kotlinx.coroutines.app
import kotlinx.coroutines.*

suspend fun longTask() = coroutineScope {
   launch {
       delay(1000)
       val name = coroutineContext[CoroutineName]?.name
       println("[$name] Finished task 1")
   }
   launch {
       delay(2000)
       val name = coroutineContext[CoroutineName]?.name
       println("[$name] Finished task 2")
   }
}

fun main(): Unit = runBlocking {
   val job = launch(CoroutineName("Parent")) {
       longTask()
   }
   delay(1500)
   job.cancel()
}
Cancellation in coroutineScope

Twitter example using coroutineScope

Unlike coroutine builders, if there’s an exception in coroutineScope or any of its children, it cancels all other children and rethrows it. This is why using coroutineScope would fix our previous “Twitter example.” To show that the same exception is rethrown, we have changed a generic Error into a concrete ApiException.

package kotlinx.coroutines.app
import kotlinx.coroutines.*

data class Details(val name: String, val followers: Int)
data class Tweet(val text: String)
class ApiException(
   val code: Int,
   message: String
) : Throwable(message)

fun getFollowersNumber(): Int =
   throw ApiException(500, "Service unavailable")

suspend fun getUserName(): String {
   delay(500)
   return "marcinmoskala"
}

suspend fun getTweets(): List<Tweet> {
   return listOf(Tweet("Hello, world"))
}

suspend fun getUserDetails(): Details = coroutineScope {
   val userName = async { getUserName() }
   val followersNumber = async { getFollowersNumber() }
   Details(userName.await(), followersNumber.await())
}

fun main() = runBlocking<Unit> {
   val details = try {
       getUserDetails()
   } catch (e: ApiException) {
       null
   }
   val tweets = async { getTweets() }
   println("User: $details")
   println("Tweets: ${tweets.await()}")
}
Changing a generic Error into ApiException

Starting concurrent calls in suspending function

This makes coroutineScope a perfect candidate for most cases when we need to start a few concurrent calls in a suspending function.

Press + to interact
suspend fun getUserProfile(): UserProfileData =
coroutineScope {
val user = async { getUserData() }
val notifications = async { getNotifications() }
UserProfileData(
user = user.await(),
notifications = notifications.await(),
)
}

As mentioned, we often use coroutineScope to wrap a ...