【问题标题】:Providing Dispatches.Main for runBlocking hang the Android App. Why?为 runBlocking 提供 Dispatches.Main 挂起 Android App。为什么?
【发布时间】:2020-12-25 10:38:35
【问题描述】:

当我在 Android 中运行下面的代码时,它运行良好。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking {
            launch { 
                Log.d("Track", "main runBlocking pre       : ${Thread.currentThread().name}")
                delay(500)
                Log.d("Track", "main runBlocking post      : ${Thread.currentThread().name}")
            }
        }
    }

打印出来

Track: main runBlocking pre       : main
Track: main runBlocking post      : main

但是,如果我将 Main 上下文提供给 runBlocking,如下所示

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking(Dispatchers.Main) { // Provide Dispatchers.Main
            launch { 
                Log.d("Track", "main runBlocking pre       : ${Thread.currentThread().name}")
                delay(500)
                Log.d("Track", "main runBlocking post      : ${Thread.currentThread().name}")
            }
        }
    }

它挂起并且没有运行它。

注意:Dispatchers.Main 正在使用

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'

为什么挂了?

我认为不向runBlocking 提供Dispatchers.Main 是让它在主线程中运行,这与提供Dispatchers.Main 相同。是不是我理解错了?

注意: 我使用的库如下

    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.21"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    runBlocking 的默认调度程序是一个自定义调度程序,它使用调用它的线程来运行协程的延续。这就是为什么当您从 runBlocking 协程块中登录时,它会报告它在主线程上。

    但是,这与在Dispatchers.Main. Dispatchers.Main 上运行某些东西不同,它通过将代码块作为可运行文件发布到主处理程序来处理协程延续。但是,该处理程序当前正在运行此onCreate 方法,并且在onCreate 返回之前无法处理其队列中的其他消息。但是runBlocking 在其子协程返回之前不会返回,所以onCreate 永远不会返回。

    另一方面,默认的runBlocking 调度程序甚至在返回之前直接在当前线程上运行延续。它甚至不知道处理程序。如果您使用默认调度程序从runBlocking 内部启动一个协程到Dispatchers.main,我想您会遇到同样的问题。

    【讨论】:

    • 我可以假设runBlocking 默认不在Dispatchers.Main 上运行,尽管它是在main 线程上运行的状态吗?
    • 它在哪里说它在主线程上运行?
    • 如果我用runBlocking { Log.d("Track", "${Thread.currentThread()}") } 进行实验。它打印出Thread[main @coroutine#5,5,main]
    • 而在kotlinlang.org/docs/reference/coroutines/…中,还提到了When launch { ... } is used without parameters, it inherits the context (and thus dispatcher) from the CoroutineScope it is being launched from. In this case, it inherits the context of the main runBlocking coroutine which runs in the main thread.
    • @Elye,你说得对,它在主线程上运行,但这与使用Dispatchers.Main 运行不同。我修改了我的答案来解释它。
    猜你喜欢
    • 2019-10-14
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2017-10-17
    • 2021-06-09
    • 2012-12-02
    • 2012-02-17
    相关资源
    最近更新 更多