In our simple working example, GlobalScope is the coroutine scope for the launched coroutine:
fun main() {
GlobalScope.launch {
delay(500)
println("Coroutines")
}
println("Hello")
Thread.sleep(1000)
}
A coroutine scope defines the lifetime of a coroutine. Coroutines within GlobalScope can exist for the lifetime of our application. This is similar to threads that will exist for the lifetime of the application if not cleaned up properly. The concept of coroutine scope allows us to restrict our coroutines so that we can specify contexts and life cycles within our application. This concept is known as structured concurrency.
We can create our own coroutine scope that ties into our applications' existing life cycles. For example, if we're working on an Android app, we might want a coroutine scope bound to the Activity life cycle. We can accomplish that by writing something like this:
class ViewModel {
private val mainScope = MainScope()
init {
mainScope.launch {
// fetch data
}
}
fun destroy() {
mainScope.cancel()
}
}
With this code, we've created our own scope, named mainScope, that is tied to the lifetime of the enclosing ViewModel class. As long as we clean up our scope in the destroy() method, any running coroutines will be cleaned properly and the resources will be released.
By leveraging CoroutineScope, we can help ensure that our coroutines are cleaned up correctly and run as efficiently as possible.