所以,我让这个代码在" onBindViewHolder" Recycler的适配器方法:
launch(UI) {
val bitmapDrawable = loadLargeBitmapDrawable()
imageView.setImageDrawable(bitmapDrawable)
}
这冻结了我的应用程序几秒钟,锁定了我的主线程。
但后来我改为:
launch { // <- I removed the "UI"
val bitmapDrawable = loadLargeBitmapDrawable()
launch(UI) { //Launch the UI coroutine inside the other
imageView.setImageDrawable(bitmapDrawable)
}
}
为什么会这样?协同程序的目的是在同一个线程(UI)中使事物异步吗? 有人可以解释为什么我必须在另一个协程范围内运行UI协程?
答案 0 :(得分:12)
协同程序的目的是在同一个线程(UI)中使事物异步吗?
你认为协同程序的魔法比实际更多。如果你的loadLargeBitmapDrawable()
函数不能暂停,但只是占用它的线程直到完成,Kotlin就无法做到这一点。当你说launch(UI)
时,你命令在UI线程上运行该函数。
你的第二个例子是颠倒的,它在CommonPool
上下文(这是默认值)中执行,然后将任务发布到UI线程;一个更自然的说法是这样的(我在我的代码中使用它,目的与你完全相同):
launch(UI) {
val bitmapDrawable = withContext(CommonPool) {
loadLargeBitmapDrawable()
}
imageView.setImageDrawable(bitmapDrawable)
}
withContext
将暂停您在UI线程上启动的协同程序,将重量级操作提交到公共线程池,然后在UI线程上恢复其结果的协同程序。现在,您可以将位图推送到imageView
。
在我的代码中,我不使用全局CommonPool
上下文,因为它不在我的控制之下,我不知道它在做其他事情有多忙。相反,我将自己的线程池创建为顶级全局变量:
val threadPool = Executors.newCachedThreadPool().asCoroutineDispatcher()
然后我可以说withContext(threadPool) { ... }
并且放心我的线程没有被我自己的任何其他代码使用。