为什么这个Kotlin Coroutine会冻结界面?

Dan*_*ira 4 android kotlin kotlin-coroutines

所以,我在"onBindViewHolder"回收器的适配器方法中运行了这个代码:

 launch(UI) {
            val bitmapDrawable = loadLargeBitmapDrawable()          
            imageView.setImageDrawable(bitmapDrawable)
  }
Run Code Online (Sandbox Code Playgroud)

这让我的应用程序冻结了几秒钟,锁定了我的主线程.

但后来我改为:

launch { // <- I removed the "UI"
            val bitmapDrawable = loadLargeBitmapDrawable()  

            launch(UI) { //Launch the UI coroutine inside the other
                imageView.setImageDrawable(bitmapDrawable)
            }      

  }
Run Code Online (Sandbox Code Playgroud)

为什么会这样?协同程序的目的是在同一个线程(UI)中使事物异步吗?有人可以解释为什么我必须在另一个coroutine范围内运行UI协程?

Mar*_*nik 12

协同程序的目的是在同一个线程(UI)中使事物异步吗?

你可以为协同程序赋予更多魔力.如果你的loadLargeBitmapDrawable()函数不是可挂起的,但只是占用它的线程直到完成,Kotlin就无法做到这一点.当你说launch(UI),你命令该功能在UI线程上运行.

你的第二个例子是颠倒的,它在CommonPool上下文中执行(这是默认值),然后将任务发布到UI线程; 一个更自然的说法是这样的(我在我的代码中使用它,与你的目的完全相同):

launch(UI) {
    val bitmapDrawable = withContext(CommonPool) {
        loadLargeBitmapDrawable() 
    }
    imageView.setImageDrawable(bitmapDrawable)
}
Run Code Online (Sandbox Code Playgroud)

withContext将暂停您在UI线程上启动的协同程序,将重量级操作提交到公共线程池,然后在UI线程上恢复其结果的协同程序.现在你可以将位图推送到imageView.

在我的代码中,我不使用全局CommonPool上下文,因为它不在我的控制之下,我不知道它在做其他事情有多忙.相反,我创建自己的线程池作为顶级全局变量:

val threadPool = Executors.newCachedThreadPool().asCoroutineDispatcher()
Run Code Online (Sandbox Code Playgroud)

然后我可以说withContext(threadPool) { ... }并且放心我的线程没有被任何其他代码使用,而是我自己的代码.