Почему необходимо добавить «Dispatchers.Main» к корневому заданию реализации Activity-CoroutineScope? - PullRequest
0 голосов
/ 15 ноября 2018
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()
    } 
}

Этот пример скопирован из справочника сопрограмм и расширен сопрограммой launch(Dispatchers.Main).Я не понимаю, зачем + Dispatchers.Main в строке 4.Если я удалю эту часть, сопрограмма launch будет отменена в любом случае, если действие будет уничтожено.Так в чем причина Dispatchers.Main?Почему Dispatchers.IO тоже не добавлено?

Ответы [ 3 ]

0 голосов
/ 15 ноября 2018

Во-первых, я не эксперт в корутинах:

Первый вопрос: Я не понимаю, почему + Dispatchers.Main в строке 4 необходимо. Если я удалю эту часть, сопрограмма запуска будет отменена в любом случае, если действие будет уничтожено. Так в чем же причина Dispatchers.Main?

У вас есть Задание , связанное с жизненным циклом активности и Dispatchers.Main , которое связано с диспетчером основных потоков Android и работает с пользовательским интерфейсом. объекты

выглядит довольно аккуратно. Если ваша деятельность разрушается, вы отменяете задание, а если основной поток завершается (например, возникает исключение), вы отменяете задание.

2-й вопрос: Почему не добавляется Dispatchers.IO?

В этом случае нет смысла переходить на другой поток, находящийся в главном потоке приложения, потому что действие находится в MainThread

0 голосов
/ 16 ноября 2018

Когда вы написали это:

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.

0 голосов
/ 15 ноября 2018

Начиная с Kotlin 1.3 вам нужна новая сопрограмма от CoroutineScope до launch. В вашем примере вы создаете область действия как val действия:

override val coroutineContext: CoroutineContext 
    get() = job + Dispatchers.Main

Объем сопрограммы состоит из разных частей, например, диспетчер и работа. Диспетчер используется для запуска сопрограммы - выберите поток - задание используется в качестве родителя сопрограмм, созданных из этой области.

Если вы укажете другого диспетчера при вызове метода launch, этот диспетчер переопределит стандартный диспетчер:

launch(Dispatchers.Main) 

В вашем примере данный Dispatchers.Main переопределяет стандарт Dispatchers.Main - ничего не происходит.

Обычно вы определяете стандартного диспетчера, который используется в большинстве мест вашей деятельности, и указываете только специального диспетчера, если требуется.

...