在协程上访问 Dispatchers.IO 上的视图不会使应用程序崩溃,为什么?但是Android中UI只能通过MAIN Thread访问

问题描述 投票:0回答:2

这是我正在使用的代码:

 (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

这是为什么?

android kotlin kotlin-coroutines
2个回答
0
投票

它为我抛出(在

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
,看看它是否会改变任何东西

(我对协程的底层管理不太了解,我可能完全没有根据。我只是指出这是一个可能的调查路线,因为你看到了奇怪的行为!)


0
投票

如果您查看 Dispatchers.IO 的实现,您会发现它还使用 DefaultScheduler,并允许按需创建至少 64 个线程。 Dispatchers.Default 和 Dispatchers.IO 隐式链接在一起,因为它们使用相同的线程池。看看 Manuel Vivo 写的这篇好文章这里

© www.soinside.com 2019 - 2024. All rights reserved.