Kotlin协程join()在IO线程调用仍阻塞UI线程的问题及优化咨询
问题根源
- 核心问题出在你在UI线程(点击事件回调默认运行在主线程)调用了
runBlocking:runBlocking的设计目的是桥接阻塞代码和协程代码,它会阻塞当前调用它的线程,直到其内部所有协程执行完毕才会返回。哪怕你内部的launch指定了Dispatchers.IO,runBlocking本身会把主线程卡到10秒延迟跑完才释放,自然会阻塞UI。 - 冗余操作:
async启动的协程不需要先调用join()再调用await(),单独调用await()就已经会等待协程执行完成并返回结果,join()属于多余调用。
正确实现方案
安卓平台做UI相关的异步操作,推荐使用和组件生命周期绑定的协程Scope,避免内存泄漏,也不会阻塞主线程:
@ExperimentalCoroutinesApi fun btn(view: android.view.View) { binding.firstText.text = "" // 使用lifecycleScope,自动和当前Activity/Fragment生命周期绑定 lifecycleScope.launch { // 网络/耗时操作放在IO线程执行 val variable1 = async(Dispatchers.IO) { delay(10000) "I am the guy who comes 10 secs later\nDid you miss me?" } // 直接await即可,不会阻塞主线程,只是挂起当前协程 val a = variable1.await() Log.d(TAG, "btn: ******************************************************* $a") // lifecycleScope默认运行在主线程,不需要额外切线程调用runOnUiThread binding.firstText.text = a } }
如果只有单个耗时任务,你甚至可以不用async,直接用withContext简化写法:
@ExperimentalCoroutinesApi fun btn(view: android.view.View) { binding.firstText.text = "" lifecycleScope.launch { val a = withContext(Dispatchers.IO) { delay(10000) "I am the guy who comes 10 secs later\nDid you miss me?" } Log.d(TAG, "btn: ******************************************************* $a") binding.firstText.text = a } }
lifecycleScope.launch启动的协程默认运行在主线程,遇到await/withContext时只会挂起协程,不会阻塞主线程,主线程可以继续响应其他操作,等耗时操作执行完后会自动恢复执行后续逻辑。
内容的提问来源于stack exchange,提问作者Onwuka Daniel
相关产品推荐
相关产品推荐

