Why must "Dispatchers.Main" be added to the root job of an implementation of an Activitys CoroutineScope?

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?

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.

(why) must you, (why) must you ? meaning, definition, what is (why) must you ?: used to tell someone that their behaviou: Learn more. Affirmative (+) form. Must comes first in the verb phrase (after the subject and before another verb): She must have lots of friends. Must can’t be used with another modal verb. This must be your sister. Not: This must can be your sister. or This can must be your sister.

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.

Why Must I Always Explain?, Music video by Van Morrison performing Why Must I Always Explain? (Audio). (C) 2015 Exile Duration: 3:53 Posted: 28 Aug 2015 English Language Learners Definition of must — used to say that something is required by a rule or law somewhat formal in US English — used to say that someone should do something — used to say that something is very likely

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

Van Morrison - Why Must I Always Explain? (Audio), Directed by Roy Del Ruth. With Terry Moore, Debra Paget, Bert Freed, Juli Reding. Debra Paget commits a murder for which Terry Moore (as club singer Lois  Directed by Roy Del Ruth. With Terry Moore, Debra Paget, Bert Freed, Juli Reding. Debra Paget commits a murder for which Terry Moore (as club singer Lois King) is arrested, tried, and condemned to die.

Why Must I Die? (1960), Why must I eat healthy food ? If you eat healthy food , your body will be healthy , too . Food is the fuel that gives you energy . Your body needs food to make and  A: He must be a true man because the justice of God requires that the same human nature which has sinned should pay for sin. He must be a righteous man because one who himself is a sinner he cannot pay for others.

Why Must I Eat Healthy Food?, The arts bring meaning to our lives and spirit to our culture -- so why do we expect artists to Duration: 6:41 Posted: 15 Mar 2018 There are three main reasons why the world must hold the CCP accountable for the first global pandemic in a century. Morality The first reason the CCP must be held accountable for the pandemic is

Hadi Eldebek: Why must artists be poor?, We must love one another because God is love and He showed it by sending His Son as the propitiation for our sins. John states the commandment and gives the reason for it (4:7-8). Then he points us to the supreme illustration of love in the whole world, the Father’s love in sending His Son to die for our sins (4:9-10).

Comments
  • Could then protected lateinit var job: Job be removed and simply replaced by override val coroutineContext: CoroutineContext = Job() + Dispatchers.Main and a further replacement in onDestroy by coroutineContext.cancel()?
  • Yes, I believe this will work. The only thing it changes it that the Job() is there before onCreate() is called, so you can start a coroutine before the activity got to the create lifecycle point. I think it's more of a theoretical than a practical difference.