我正在尝试kotlinx.coroutines(版本:1.2.0)。这是一个简单的测试代码块:
GlobalScope.launch {
Logger.i("${Thread.currentThread()}, ${Looper.myLooper() == Looper.getMainLooper()}")
text_view.text = "test"
}
打印的日志是:
Thread[DefaultDispatcher-worker-2,5,main], false
如日志所示,我们不在Android主线程(即UI线程)上。但是,在我们将此工作线程上的文本设置为text_view
并且正确地将“ test”设置为text_view
之后,上面的代码不会引发异常。是什么原因?
更新1:
在delay(10000L)
之前添加setText()
会导致异常,而较短的时间(例如在我的测试中为1000L的冷启动调试运行)不会。因此,这似乎是一个Android问题。但是仍然有一个问题,原因是什么?
更新2:
现在,我意识到这种行为与Android有关,而不是与kotlinx.coroutines有关。当onCreate()
可能尚未调用ViewRootImpl
或初始化所有performTraversals()
时,以上代码将在View
中执行。在这种情况下,也不会调用UI操作之前的checkThread()
。
答案 0 :(得分:0)
在GlobalScope
中启动协程时使用的默认调度程序由 Dispatchers.Default
表示,并使用共享的后台线程池,因此 launch(Dispatchers.Default) { ... }
使用与GlobalScope.launch { ... }
相同的调度程序。
因此,当使用launch { ... }
时不带参数时,它将从CoroutineScope
继承了上下文 (并因此调度程序)从。
在这种情况下,它继承了主线程的上下文。
因此,除非我们定义 context&dispatcher ,否则协程将在主线程上工作,从DefaultDispatcher
(在我们的情况下,再次是main)中创建新的工作线程
答案 1 :(得分:0)
与Kotlin协程无关。
即使您不应该从非UI线程调用UI函数,但并非每个Android UI函数实际上都会检查您是否在UI线程上。 TextView#setText()
是其中之一,您可以从后台线程调用它而不会遇到异常。
答案 2 :(得分:0)
GlobalScope.launch(Dispatchers.Main) {
mTvText?.text = "text" // exemple: set text in main thread
... // write also your code here
}