What is the difference between these two?
I was following a tutorial, and the teacher said we need a scope that lives as long as the app lives, created the scope manually with SupervisorJob. Doesn't GlobalScope do the same thing?
I researched about this, but couldn't find a proper explanation. Thanks.
CodePudding user response:
The difference between these two specific examples is that GlobalScope cannot be cancelled, but the other one can. When you call cancel()
on a CoroutineScope created with the CoroutineScope()
constructor function, all of its children coroutines get canceled.
GlobalScope will throw an IllegalStateException if you try to cancel()
it, because it has no Job to be a parent of coroutines that it launches.
When you call CoroutineScope()
without passing it a Job, it gets a generic Job automatically to be the parent of its coroutines. A generic parent Job like this will cancel all of its children coroutines if any of them fail. If you explicitly use SupervisorJob()
, then if any of its children fail, they won't cause all their siblings to be canceled. This is a behavior that is similar to GlobalScope, since GlobalScope coroutines have no siblings that they could cause to be cancelled through a shared parent.
The reason GlobalScope is discouraged is that it has no supervisory capabilities. It should only be used for coroutines that should run for the entire lifetime of an app session. But if you're doing important work that should not be cancelled on Android, coroutines are not a good choice anyway because they aren't handling the cases where your app is in the background. In those cases you should be using a service or WorkManager instead. So, the actual legitimate use cases for GlobalScope, or any CoroutineScope that is never cancelled, are extremely rare.
I think the reason they added @DelicateCoroutinesApi
is that so many people were misusing GlobalScope. (Probably because they unfortunately used it in the beginner documentation on how to use coroutines.) It is not correct to get around the warning by using CoroutineScope(SupervisorJob())
or CoroutineScope(Dispatchers.IO)
, etc. instead of GlobalScope, because all that does is mask the warning without changing the behavior other than creating a redundant CoroutineScope. If you have a legitimate use for GlobalScope, you should use @OptIn(DelicateCoroutinesApi::class)
to dismiss the warning.