взаимосвязь сопрограммы котлина и главного обработчика

У меня есть следующий фрагмент

 verticalLayout {
        gravity = Gravity.CENTER
        button("BUTTON").onClick {
            trace("click on process")
            runBlocking {
                trace("blocking start") // #1
                delay(20000L)  #2
                trace("blocking end")  // #3
            }
            trace("click process end")
        }
    }

trace - это функция, определенная как служебная функция для выхода из сообщений с использованием Log.e с текущим именем потока

когда я нажимаю кнопку, весь код запускается, как ожидалось, и журналы показывают, что все функции трассировки вызываются в журнале основного потока для # 3 появляется после # 1 в течение 20000L мс, и в диалоговом окне ANR не отображается

но происходили странные вещи: в течение 20000L мс кнопка удерживала нажатое состояние, даже когда я отпускал кнопку сразу после щелчка, затем я понял, что нажатое состояние восстанавливается, когда метод onClick заканчивается,

У меня была необработанная концепция, что сопрограмма - это магия компилятора, использующая CPS для преобразования кода в функцию стиля обратного вызова, например,

delay(20000L,callback = { trace("blocking end ")})

так что у меня есть следующие вопросы

  1. в конце концов, кто и когда на самом деле вызывает обратный вызов (например, трассировка ("блокирующий конец")), если ответ - это основной цикл или что-то в этом роде (для nodejs, возможно, цикл событий), должны ли мы адаптировать структуру для сопрограммы и позволить сопрограмме помещать событие в очередь?
  2. говоря, что сопрограмма на самом деле является магией компилятора, можем ли мы написать тот же код, что и приведенный выше фрагмент, который не запускает ANR, но сохраняет нажатое состояние для 20000L?

person Minami    schedule 12.06.2017    source источник
comment
Похоже, вы делаете много предположений, которых на самом деле делать не обязательно. Вызов runBlocking создает сопрограмму, которая выполняется в том же потоке, в котором она вызывается, и блокирует поток в точках приостановки. Поэтому вызов delay просто блокирует поток, в котором выполняется onClick-функция.   -  person marstran    schedule 12.06.2017
comment
Непонятно, чего вы пытаетесь достичь. Текущее поведение объясняет @marstran. Вы не должны вызывать delay в сочетании с runBlocking из потока пользовательского интерфейса. Либо переместите его в другой поток, вызвав launch(CommonPool), либо не вызывайте delay.   -  person xap4o    schedule 12.06.2017


Ответы (1)


Вы используете runBlocking с таким названием, потому что он блокирует вызываемый поток на время выполнения сопрограммы. В вашем конкретном случае вы блокируете поток пользовательского интерфейса с помощью runBlocking.

Вы можете заменить runBlocking на launch(UI), чтобы запустить фоновую сопрограмму в потоке пользовательского интерфейса без блокировки потока пользовательского интерфейса. Вы можете узнать больше о различных способах работы с сопрограммами в Руководстве в kotlinx.coroutines и в Руководство по программированию пользовательского интерфейса с помощью сопрограмм.

person Roman Elizarov    schedule 21.06.2017