Как CoroutineScope (job + Dispatchers.Main) может работать в главном потоке / пользовательском интерфейсе? - PullRequest
3 голосов
/ 18 февраля 2020

Если операции внутри CoroutineScope(job+Dispatchers.Main){...} выполняются в главном потоке, то, как получается, это не нарушает требование Android о том, что медленные (блокирующие) операции (Networking et c.) Запрещены для запуска на главном потоке / Пользовательский интерфейс? Я могу запустить блокирующие операции с этой областью, и пользовательский интерфейс вообще не зависает.

Буду признателен, если кто-нибудь сможет объяснить, что происходит под капотом. Я предполагаю, что это похоже на то, как JavaScript управляет операциями блокировки с событием l oop, но я изо всех сил пытаюсь найти какие-либо соответствующие материалы.

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Я предполагаю, что это похоже на то, как JavaScript управляет операциями блокировки с событием l oop

Да, это правильно, событие l oop важно, чтобы заставить сопрограммы работать. В основном, когда вы пишете это:

uiScope.launch {
    delay(1000)
    println("A second has passed")
}

, оно компилируется в код, который имеет тот же эффект, что и этот:

Handler(Looper.mainLooper()).postDelayed(1000) { println("A second has passed") }

Основная концепция - продолжение , объект, который реализует конечный автомат, который соответствует последовательному коду, который вы написали в приостановленной функции. Когда вы вызываете delay или любую другую приостановляемую функцию, метод точки входа продолжения возвращает специальное значение COROUTINE_SUSPENDED. Позже, когда какой-то внешний код обнаруживает возвращаемое значение приостановленной функции, он должен вызвать continuation.resume(result). Этот вызов будет перехвачен ответственным диспетчером, который опубликует этот вызов как событие в событии GUI l oop. Когда обработчик событий снят с очереди и выполняется, вы возвращаетесь в конечный автомат, который выясняет, где возобновить выполнение.

Вы можете просмотреть этот ответ для более подробного примера используя Continuation API.

1 голос
/ 19 февраля 2020

Запуск блокирование операций и запуск приостановка операции на CoroutineScope(Dispatchers.Main) - это две разные вещи.

delay() - это функция приостановки, и она не блокируется

CoroutineScope(Dispatchers.Main){
    delay(6000)
}

Пока Thread.sleep() блокирует, а приведенный ниже код вызова вызовет ANR

CoroutineScope(Dispatchers.Main){
    Thread.sleep(6000)
}

Я предлагаю вам проверить Kotlin разговор сопрограмм Романа Елизарова на Kotlinconf 2017, особенно ту часть, где он бежит 100 000 delay()

...