弃用警报
此代码使用旧的Coroutines API。如果您使用的是kotlinx-coroutines 1.1.0或更新,此代码对您
最初的问题是:
我在我的Android应用中发现此特定代码会阻止UI线程:
runBlocking {
async(CommonPool) {
Thread.sleep(5000)
}.await()
}
textView.text = "Finish!"
我一直在使用Coroutines来完成多个任务,它们永远不会阻止UI线程,如文档中可以阅读:
。Coroutines提供了一种避免堵塞线的方法
但奇怪的是,此代码:
runBlocking {
async(CommonPool) {
launch(CommonPool) {
Thread.sleep(5000)
runOnUiThread { textView.text = "Finish!" }
}
}.await()
}
行为符合预期;不要阻止,等待五秒钟,然后打印结果(我需要在完成sleep
之后更新UI(
文档说async
和launch
可以独立使用,不需要合并。实际上, 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()
}
}
}
}
note :这篇文章可以追溯到Coroutines的预释放版本。我更新了调度器的名称以匹配发布版本。
runBlocking
并不是在UI线程上启动Coroutine的方法,因为顾名思义,它将阻止托管线程直到完成Coroutine。您必须在Main
上下文中进行launch
,然后切换到重量级操作的Default
上下文。您还应该放下async-await
对并使用withContext
:
button1.setOnClickListener {
launch(Main) {
withContext(Default) {
Thread.sleep(5000L)
}
textView1.text = "Done! UI was not blocked :-)"
}
}
withContext
将暂停Coroutine,直到完成,然后在父上下文中恢复它,即Main
。
作为文档告诉我们:
[
runBlocking
]运行新的Coroutine,阻止当前线程中断直到完成为止。不应从Coroutine使用此功能。它被设计为桥梁常规的阻止代码限制为悬挂样式编写的库,在main
函数和 tests> tests 中使用。
如引用,它经常用于与常规Coroutines一起使用的测试以及main
方法以等待Coroutines的完成。
此外,本教程将有助于了解其用例。
我很抱歉这个较晚的答案,但我希望您发现它有帮助。
1-因为在第一种情况下
runBlocking {
async(CommonPool) {
Thread.sleep(5000L)
}.await()
}
runBlocking{}
块将阻止主线程直到内部代码完成为止,然后当我们进入runBlocking{}
块内部时,我们发现您在async{}
块上等待您等待,因此我们必须等到async{}
内部的内容,以便我们必须等待等待5秒。那就是为什么此代码会阻止主线程。
2-但在第二种情况下: -
runBlocking {
async(CommonPool) {
launch(CommonPool) {
Thread.sleep(5000)
runOnUiThread { textView.text = "Finish!" }
}
}.await()
}
您没有在launch{}
块上等待(通过使用.join()
(,因此您在async{}
块中唯一做的是启动Coroutine而不等待它完成。就像async{}
块是空的一样,因此async{}.await()
和runBlocking{}
不会等待任何东西完成。这就是为什么第二种情况不会阻止主线程的原因。我希望这可以回答。