Когда вы написали это:
launch(Dispatchers.Main) {
try {
delay(Long.MAX_VALUE)
} catch (e: Exception) {
// e will be a JobCancellationException if the activty is destroyed
}
}
, вы, возможно, не поняли, что launch
фактически вызывается с вашим ScopedAppActivity
в качестве получателя.Таким образом, вы эффективно написали
this.launch(Dispatchers.Main) { ... }
launch
- это функция расширения для CoroutineScope
, и она будет использовать coroutineContext
в качестве отправной точки, комбинируя ее с тем, что вы указали в скобках.Итак, в вашем случае эффективный контекст равен
job + Dispatchers.Main + Dispatchers.Main
Как вы можете себе представить, это равно
job + Dispatchers.Main
, поэтому, когда вы удаляете Dispatchers.Main
из вашего coroutineContext
,ничего не меняется.
Так в чем причина Dispatchers.Main?
Преимущество предоставления Dispatchers.Main
в coroutineContext
состоит в том, что вам не нужнопредоставляйте его каждый раз, так что вы можете просто написать
launch { ... }
, и блок внутри launch
останется в потоке GUI, что является наиболее естественным способом использования сопрограмм в Android и других приложениях GUI.
Почему Dispatchers.IO тоже не добавляется?
Поскольку эта строка не об объявлении всех диспетчеров, которые вы будете использовать, а об использовании по умолчанию, она не 'Имеет смысл предоставить более одного.
На другом уровне CoroutineContext
- это не список (что подразумевается оператором +
), а карта.Синтаксис +
работает, потому что каждый добавляемый вами объект объявляет свой собственный ключ карты, который +
использует для помещения его во внутреннюю карту контекста.Так что на самом деле невозможно поместить двух диспетчеров в один CoroutineContext
.