为什么此coroutine阻止UI线程



弃用警报

此代码使用旧的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(

(

文档说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()
            }
        }
    }
}

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{}不会等待任何东西完成。这就是为什么第二种情况不会阻止主线程的原因。我希望这可以回答。

相关内容

  • 没有找到相关文章

最新更新