Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/208.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 为什么kotlin协程可以在另一个线程上操作UI元素_Android_Multithreading_Kotlin_Coroutine_Kotlin Coroutines - Fatal编程技术网

Android 为什么kotlin协程可以在另一个线程上操作UI元素

Android 为什么kotlin协程可以在另一个线程上操作UI元素,android,multithreading,kotlin,coroutine,kotlin-coroutines,Android,Multithreading,Kotlin,Coroutine,Kotlin Coroutines,我正在尝试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 如日志所示,

我正在尝试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设置为
text\u view
并且“test”正确设置为
text\u view
之后,上面的代码不会引发异常。原因是什么

更新1:

setText()
之前添加
delay(10000L)
将导致异常,而较短的时间(如我在冷启动调试运行测试中的1000L)不会导致异常。所以这似乎是安卓系统的问题。但还是那个问题,原因是什么

更新2:


现在我意识到这种行为与Android有关,而不是与kotlinx.coroutines有关。当
ViewRootImpl
可能没有调用
performTraversals()
或初始化所有
视图时,上述代码在
onCreate()
中执行。在这种情况下,也不会调用UI操作之前的
checkThread()

GlobalScope
中启动协同路由时使用的默认调度程序由
调度程序表示。默认调度程序使用共享后台线程池,因此
启动(Dispatchers.default){…}
使用与
GlobalScope.launch{…}
相同的调度程序

因此,当在没有参数的情况下使用
launch{…}
时,它会从要从中启动它的
CoroutineScope
继承上下文(从而继承dispatcher)

在本例中,它继承主线程的上下文



因此,除非我们定义上下文和调度程序,否则协同程序将在主线程上工作,从
DefaultDispatcher
(在我们的例子中也是主线程)。

默认调度程序,在
全局范围
中启动协同程序时使用,由调度程序表示。默认值使用共享后台线程池,因此
launch(Dispatchers.Default){…}
使用与
GlobalScope.launch{…}
相同的调度程序

因此,当在没有参数的情况下使用
launch{…}
时,它会从要从中启动它的
CoroutineScope
继承上下文(从而继承dispatcher)

在本例中,它继承主线程的上下文



因此,除非我们定义上下文和调度程序,否则协程将在主线程上工作,从
DefaultDispatcher
(在我们的例子中也是主线程)。

实际上与Kotlin协程无关


即使您不应该从非UI线程调用UI函数,但并不是每个Android UI函数都会检查您是否在UI线程上
TextView#setText()
就是其中之一,您可以从后台线程调用它而不会出现异常

与Kotlin的合作项目毫无关系

 GlobalScope.launch(Dispatchers.Main) {
            mTvText?.text = "text" // exemple: set text in main thread
            ... // write also your code here
        }


即使您不应该从非UI线程调用UI函数,但并不是每个Android UI函数都会检查您是否在UI线程上
TextView#setText()
就是其中之一,您可以从后台线程调用它而不会出现异常

您需要从
Dispatcher
提供主线程,这将使它在主线程上运行。这不是问题所在,对吗?他在问为什么会出现这种行为。@ywwynm您使用的是
CorountineScope
?@BramSinke否。我只使用上面显示的代码。所以,更新2:之后,看起来您找到了正确的答案。您需要从
调度程序提供主线程,使其在主线程上运行。这不是问题,对吗?他问为什么会有这种行为。@ywwynm您使用的是
CorountineScope
?@BramSinke否。我只使用上面显示的代码。所以,更新2:之后,看起来您找到了正确的答案?抱歉,但我认为您不正确。关于这个问题,请看我的第一次更新。你能在这里参考吗,如果还有任何疑问,请告诉我。我必须说我也尝试过
GlobalScope.launch(Dispatchers.IO)
或其他Dispatchers或类似的
newSingleThreadContext
。这是同样的结果。我只是简化了问题的代码。为了确保您的项目中有
实现'org.jetbrains.kotlinx:kotlinx coroutines android:1.2.0'
,这也让您可以访问android
Dispatchers.Main
coroutine dispatcher。在GlobalScope中启动coroutines时使用的默认dispatcher,由Dispatchers.Default表示,并使用共享的后台线程池,因此launch(Dispatchers.Default){…}使用与GlobalScope.launch{…}相同的调度器。抱歉,我认为您的说法不对。关于这个问题,请看我的第一次更新。你能在这里参考吗,如果还有任何疑问,请告诉我。我必须说我也尝试过
GlobalScope.launch(Dispatchers.IO)
或其他Dispatchers或类似的
newSingleThreadContext
。这是同样的结果。我只是简化了问题的代码。为了确保您的项目中有
实现'org.jetbrains.kotlinx:kotlinx coroutines android:1.2.0'
,这也让您可以访问android
Dispatchers.Main
coroutine dispatcher。在GlobalScope中启动coroutines时使用的默认dispatcher,由Dispatchers.Default表示,并使用共享的后台线程池,因此launch(Dispatchers.Default){…}使用与GlobalScope.launch{…}相同的调度器。否<代码>文本视图#setText()
也将被选中。@ywwynm您确定吗?我在资料里找不到不
 GlobalScope.launch(Dispatchers.Main) {
            mTvText?.text = "text" // exemple: set text in main thread
            ... // write also your code here
        }