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 ...