Android kotlin协同程序和主处理程序关系

Android kotlin协同程序和主处理程序关系,android,kotlin,coroutine,anko,Android,Kotlin,Coroutine,Anko,我有下面的片段 verticalLayout { gravity = Gravity.CENTER button("BUTTON").onClick { trace("click on process") runBlocking { trace("blocking start") // #1 delay(20000L) #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注销消息

当我单击该按钮时,所有代码按预期运行,日志显示所有跟踪函数都在主线程中调用 在20000L毫秒内,3的日志出现在1之后,且不显示ANR对话框

但是奇怪的事情发生了,在20000L毫秒的过程中,即使我在点击后立即松开按钮,按钮仍保持按下状态,然后我意识到onClick方法结束时按下的状态会恢复

我有一个原始的概念 coroutine是一种编译器魔法,它使用CPS将代码转换为如下回调风格的函数

delay(20000L,callback = { trace("blocking end ")})
所以我有以下几个问题

最后,谁和何时实际调用callbacke.g traceblocking end如果答案是nodejs的主循环器或其他东西,可能是eventloop,那么我们是否应该调整协同路由的框架并让协同路由将事件放入队列? 如果说协同程序实际上是一种编译器魔法,那么我们是否可以编写与上面的代码片段相同的代码,该代码片段不会触发ANR,但会保持20000L的按下状态? 您使用的是runBlocking,它以这种方式命名,因为它会在协同程序执行期间阻塞调用它的线程。在您的特定情况下,您正在使用runBlocking阻塞UI线程


您可以用launchUI替换runBlocking,在UI线程上启动后台协同程序,而不阻塞UI线程。您可以在和中了解更多有关使用协同程序的各种方法。

您似乎在做很多您实际上不必做的假设。对runBlocking的调用创建了一个协同程序,该程序在调用它的同一线程上运行,并在挂起点上阻塞该线程。因此,对delay的调用只会阻塞onClick函数正在运行的线程。不清楚您想要实现什么。当前行为由@marstran解释。您不应该从UI线程调用delay和runBlocking。通过调用launchCommonPool将其转移到其他线程,或者不调用delay。