在异步执行任务时阻塞 Android 上的主线程

Blocking the main thread on Android while doing task asynchronously

我一直在努力理解 Android 上多线程与异步编程之间的区别。主要是,为什么需要从主线程中删除一个长 运行 任务,即使该任务是通过协程之类的异步方式完成的。

我的解释是,即使长 运行 任务可能是异步的,它仍然在 UI 线程上完成。因此,即使异步代码没有阻塞,重要的是工作而不是阻塞。这似乎有道理。

然而,也许只是我不知道的语言的细微差别,但是像 JavaScript 这样不能将其工作委托给任何其他单独线程的单线程语言也可以异步工作,但是您可以在 JavaScript 异步函数中执行较长的 运行 任务,并且永远不会收到任何错误,表明您在主线程上做了太多工作,并看到 UI 性能下降。

为什么在 Android 上即使任务被挂起,您仍然必须从主线程中取出代码,而不是像 javascript 这样只依赖一个线程的语言?

Why is it that you still have to take code off the main thread on Android even if a task is suspended

你不知道。唯一的规则是

Any single event taken from the main thread's event queue shouldn't take long to handle.

其中 "long" 可能是一两毫秒以上的所有内容。

如果您在事件处理程序中执行阻塞、同步操作,它将计入该事件处理程序的执行持续时间。

如果您在事件处理程序中执行非阻塞异步操作,处理程序实际上会在启动操作后立即完成,确保稍后将另一个事件放入队列中,当手术准备就绪。

这就是协作与抢占式多线程的本质:在前一种情况下,用户代码负责将整个任务分成几个轻量级事件,而在后一种情况下,OS 强制执行它代码在做什么。由于整个 GUI 必须 运行 在单个线程上,抢占式多线程不是一个选项。

所以,具体来说,在 Kotlin 中你可以这样写

launch(Dispatchers.Main) {
    val user = makeRestCall("/users/$id")
    usernameText.text = user.name
}

还有一些 suspend fun makeRestCall(url: String).