Reputation: 4848
abstract class ScopedAppActivity: AppCompatActivity(), CoroutineScope {
protected lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
launch(Dispatchers.Main) {
try {
delay(Long.MAX_VALUE)
} catch (e: Exception) {
// e will be a JobCancellationException if the activty is destroyed
}
}
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}
This example is copied from the coroutine guide and extended by the launch(Dispatchers.Main)
coroutine. I don't understand why + Dispatchers.Main
in line 4 is needed. If I remove this part the launch
coroutine will be cancelled anyways if the Activity is destroyed. So what is the reason for Dispatchers.Main
? Why is Dispatchers.IO
not added, too?
Upvotes: 7
Views: 3184
Reputation: 200168
When you wrote this:
launch(Dispatchers.Main) {
try {
delay(Long.MAX_VALUE)
} catch (e: Exception) {
// e will be a JobCancellationException if the activty is destroyed
}
}
you may not have realized that launch
is actually invoked with your ScopedAppActivity
as the receiver. So you effectively wrote
this.launch(Dispatchers.Main) { ... }
launch
is an extension function on CoroutineScope
and it will use its coroutineContext
as the starting point, combining it with whatever you specify in the parentheses. So, in your case, the effective context is
job + Dispatchers.Main + Dispatchers.Main
As you can imagine, this is equal to
job + Dispatchers.Main
so when you remove Dispatchers.Main
from your coroutineContext
, nothing changes.
So what is the reason for Dispatchers.Main?
The advantage of providing Dispatchers.Main
in coroutineContext
is that you don't have to supply it every time, so you can just write
launch { ... }
and the block inside launch
will stay on the GUI thread, which is the most natural way to use coroutines on Android and other GUI applications.
Why is Dispatchers.IO not added, too?
Since that line is not about declaring all the dispatchers you'll use, but the default one, it doesn't make sense to provide more than one.
On another level, CoroutineContext
isn't a list (which is kind of implied by the +
operator), but a map. The +
syntax works because each object you add declares its own map key, which +
uses to put it into the context's internal map. So it's actually impossible to put two dispatchers into one CoroutineContext
.
Upvotes: 8
Reputation: 1823
First i am not an expert in Corutines:
First question: I don't understand why + Dispatchers.Main in line 4 is needed. If I remove this part the launch coroutine will be cancelled anyways if the Activity is destroyed. So what is the reason for Dispatchers.Main?
U have a Job associatted with an activity lifeCycle and Dispatchers.Main wich is associatted with the Android Main thread dispatcher and operating with UI objects:
Looks pretty neat. If ur activity is destroying u will get ur job cancelled, and if ur main thread ends(example an exception occurs), u will get ur job cancelled.
2nd question: Why is Dispatchers.IO not added, too?
It doesnt make sense, to change to another Thread being on the Main-Thread of the application in this case, because the activity lives in the MainThread
Upvotes: 1
Reputation: 6148
Since Kotlin 1.3 you need a CoroutineScope
to launch
a new coroutine.
In your example you create a scope as val
of the activity:
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
A coroutine scope consist of different parts, e.g. a dispatcher and a job. The dispatcher is used to start the coroutine - select the thread - the job is used as the parent of the coroutines created from this scope.
If you specify another dispatcher at the invocation of the launch
method, this dispatcher will override the standard dispatcher:
launch(Dispatchers.Main)
In your example the given Dispatchers.Main
overrides the standard Dispatchers.Main
- nothing happens.
Typically you define a standard dispatcher that is used in most places of your activity and only specify a special dispatcher if required.
Upvotes: 1