2

我有以下片段

 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 在 20000L 毫秒内出现在 #1 之后,并且没有显示 ANR 对话框

但奇怪的事情发生了,在 20000L ms 期间,即使我在单击后立即释放按钮,按钮仍保持按下状态,然后我意识到当 onClick 方法结束时恢复按下状态,

我有一个原始概念,协程是一种编译器魔法,使用 CPS 将代码转换为回调样式函数,如跟随

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

所以我有以下问题

  1. 最后谁和什么时候真正调用回调(例如trace(“blocking end”))如果答案是主循环器或其他东西(对于nodejs,可能是事件循环),我们是否应该为协程调整框架并让协程放置事件排队?
  2. 说协程实际上是编译器的魔法,我们可以编写与上面的代码片段相同的代码,它不会触发 ANR,而是保持 20000L 的按下状态?
4

1 回答 1

4

您正在使用runBlocking它以这种方式命名,因为它会在协程执行期间阻塞调用它的线程。在您的特定情况下,您正在使用runBlocking.

您可以替换runBlockinglaunch(UI)在 UI 线程上启动后台协程而不阻塞 UI 线程。您可以在kotlinx.coroutines指南和使用协程进行 UI 编程指南中了解有关使用协程的各种方法的更多信息。

于 2017-06-21T10:24:58.680 回答