android - 为什么这个协程会阻塞 UI 线程?

标签 android multithreading kotlin kotlin-coroutines

弃用警报

此代码使用旧的 Coroutines Api。如果您使用的是 kotlinx-coroutines 1.1.0 或更新版本,此代码对您没有用

原来的问题是:

我发现我的 Android 应用程序中的这段特定代码阻塞了 UI 线程:

runBlocking {
    async(CommonPool) {
        Thread.sleep(5000)     
    }.await()
}

textView.text = "Finish!"

我一直在为多项任务使用协程,它们从不阻塞 UI 线程,这可以在 the documentation 中阅读:

. Coroutines provide a way to avoid blocking a thread and replace it with a cheaper and more controllable operation: suspension of a coroutine

但奇怪的是,这段代码:

runBlocking {
    async(CommonPool) {
        launch(CommonPool) {
            Thread.sleep(5000)

            runOnUiThread { textView.text = "Finish!" }
        }
    }.await()
}

表现符合预期;不阻塞,等待五秒钟然后打印结果(之后我需要更新 UI,并且只有在 sleep 完成之后)

文档上说asynclaunch可以独立使用,不需要结合使用。事实上,async(CommonPool) 应该足够了。

那么这里到底发生了什么?为什么它只适用于 async+launch

更新(2021 年)

[弃用警报] 此代码使用旧的 Coroutines Api。如果您使用的是 kotlinx-coroutines 1.1.0 或更新版本,请忽略此代码

我的完整示例代码:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        button1.setOnClickListener {
            runBlocking {
                async(CommonPool) {
                    Thread.sleep(5000L)
                }.await()
            }

            textView1.text = "Finally! I've been blocked for 5s :-("
        }

        button2.setOnClickListener {
            runBlocking {
                async(CommonPool) {
                    launch(CommonPool) {
                        Thread.sleep(5000L)

                        runOnUiThread { textView1.text = "Done! UI was not blocked :-)" }
                    }
                }.await()
            }
        }
    }
}

最佳答案

注意:这篇文章可以追溯到协程的预发布版本。我更新了调度员的姓名以匹配发布版本。

runBlocking 不是在 UI 线程上启动协程的方法,因为正如其名称所示,它会阻塞托管线程,直到协程完成。您必须在 Main 上下文中启动 它,然后切换到 Default 上下文以进行重量级操作。您还应该删除 async-await 对并使用 withContext:

button1.setOnClickListener {
    launch(Main) {
        withContext(Default) {
            Thread.sleep(5000L)
        }
        textView1.text = "Done! UI was not blocked :-)"
    }
}

withContext 将挂起协程直到完成,然后在父上下文(即 Main)中恢复它。

关于android - 为什么这个协程会阻塞 UI 线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48663423/

相关文章:

android - 有没有办法在 android studio 中找到所有的 Log.d() 行

安卓 TextToSpeech : getting the audio time length

java - 如何只允许某些 int 值作为 Java 中方法的参数?

c++ - 单元测试引用关键部分类

java - java中继承下的同步静态方法行为

android - setOnCompletionListener 方法未在我的媒体播放器中调用

android - PJSIP Android 构建 NDK

java - 在 junit 中错开并行测试开始?

swift - Kotlin 相当于 %@ 在 swift

android - Kotlin - 将 List 转换为 MutableList 的最惯用方式