这是我正在使用的代码:
(application as TestApp).applicationScope.launch(Dispatchers.IO) {
println("Thread 2 "+Thread.currentThread().name)
binding.username.setText("text2")
}
(application as TestApp).applicationScope.launch(Dispatchers.Default) {
println("Thread 3 "+Thread.currentThread().name)
binding.username.setText("text3")
}
在这里,我从 Activity 访问 Dispatchers.IO 和 Dispatchers.Default 线程上的 TextView,该线程不是主线程。应用程序仍然正常运行并且不会抛出任何异常。
打印的线程名称是:
Thread 3 DefaultDispatcher-worker-4
Thread 2 DefaultDispatcher-worker-2
这是为什么?
它为我抛出(在
lifecycleScope
中使用 Fragment
):
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
这些
println
语句的输出是什么,线程名称是否不同?您在哪个线程上充气binding
?
在您的特定环境中,这些协程可能不会在不同的线程上执行。就像我运行它时一样,
IO
和Default
调度程序最终都会打印以Defaultdispatcher-worker-
开头的线程名称,这意味着它们从Default
调度程序的线程池开始。还有一个无限制调度员:
Dispatchers.Unconfined 协程调度程序在调用者线程中启动协程,但仅直到第一个挂起点。挂起后,它会恢复线程中的协程,该线程完全由调用的挂起函数决定。
由于您的协程不会挂起(例如使用
delay
),因此它们可能会在执行移动到另一个线程之前触发 UI 更新。就像那里所说的那样,Dispatchers.Unconfined
是一种边缘情况调度程序,不建议一般使用,但有可能,类似的事情正在幕后发生,从而更有效地处理调度。 (但不适合我!)您可以尝试在 UI 触摸之前为每个添加一个 delay
,看看它是否会改变任何东西
(我对协程的底层管理不太了解,我可能完全没有根据。我只是指出这是一个可能的调查路线,因为你看到了奇怪的行为!)
如果您查看 Dispatchers.IO 的实现,您会发现它还使用 DefaultScheduler,并允许按需创建至少 64 个线程。 Dispatchers.Default 和 Dispatchers.IO 隐式链接在一起,因为它们使用相同的线程池。看看 Manuel Vivo 写的这篇好文章这里