Welcome to another post! Today, let’s compare coroutineScope
and supervisorScope
in Kotlin Coroutines, something you might come across in Android interviews. We will understand the major difference between these two and try to determine when to choose coroutineScope
and when to choose supervisorScope
.
coroutineScope
coroutineScope
is a coroutine builder function in Kotlin Coroutines that suspends the current coroutine until all child coroutines within the scope complete or fail.
supervisorScope
supervisorScope
is a coroutine builder function in Kotlin Coroutines that creates a new coroutine scope with a different error-handling strategy compared to coroutineScope
. If a child coroutine within a supervisorScope
encounters an exception, it doesn’t affect other coroutines within the scope, allowing them to continue executing.
Both are coroutine builder function, but did you notice the difference between the two?
coroutineScope | supervisorScope |
if one child of this scope fails, it will cancel the scope | Even if any children fail, it will keep executing the other children within the scope. |
You got the major difference between these two. Now let’s try to understand with some actual code examples.
coroutineScope vs supervisorScope
First, let’s set up the basics. We mainly use coroutines for asynchronous tasks, such as making API calls. I won’t write an actual API call here, but I’ll just mimic an asynchronous API call function. See the code below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
data class User(val id: Int, val name: String) data class ChatRoom(val id: Int, val name: String) data class AppConfig(val config: String) suspend fun getConfig(): AppConfig { delay(5000L) return AppConfig("Config") } suspend fun getUsers(): List<User> { delay(2000L) return listOf(User(1, "Belal"), User(2, "Sunny")) } suspend fun getChatRooms(): List<ChatRoom> { delay(2500L) throw IllegalStateException("Chat rooms not ready") } |
Here, I am mimicking three API calls: getConfig()
, getUsers()
, and getChatRooms()
. The important thing to note here is that getChatRooms() will throw an Exception.
Now let’s use coroutineScope to perform the above api calls.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
fun main() = runBlocking { coroutineScope { val users = async { getUsers() } val rooms = async { getChatRooms() } val config = async { getConfig() } println(users.await()) try { println(rooms.await()) } catch (e: Exception) { e.printStackTrace() } println(config.await()) } } |
The above code will fail while getting rooms, and hence the config will never get fetched as config takes five seconds to fetch (check the initial setup code). So the exception is thrown before the config is completely fetched, and as it is a coroutineScope, it will stop everything as soon as the first exception is encountered.
Now we will try the same thing with supervisorScope.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
fun main() = runBlocking { supervisorScope { val users = async { getUsers() } val rooms = async { getChatRooms() } val config = async { getConfig() } println(users.await()) try { println(rooms.await()) } catch (e: Exception) { e.printStackTrace() } println(config.await()) } } |
If you execute the above given code then you will see that even after getting the exception in getChatRooms()
, the getConfig()
function is executed.
You can see the above output, we got the Users first then we got the exception and finally AppConfig.