我试图在0.30.0中使用最新的协程,并且在弄清楚如何使用新范围时遇到麻烦。在原始的协程中,我可以使用UI或CommonPool设置上下文,并且一切正常。
现在,我正在尝试从房间数据库中读取数据时在ViewModel中使用GlobalScope,然后我想将返回的值分配给LiveData对象。
尝试设置LiveData值时出现以下错误
java.lang.IllegalStateException:无法在 后台线程
fun getContact() {
GlobalScope.launch {
val contact = contacts.getContact() // suspended function
withContext(Dispatchers.Default) { phoneContact.value = contact }
}
}
我只看到调度程序的默认,无限制和IO,但它们都不起作用,我不知道自己在做什么错?我的主线程选项在哪里?
答案 0 :(得分:20)
您通过添加依赖关系解决了眼前的问题,但是让我在您使用GlobalScope
时添加一条注释。
在生产代码中使用GlobalScope
是一种反模式。因为类似的原因在那里
runBlocking
,以便轻松进行快速实验。由于应用程序组件的生命周期复杂,因此您尤其应避免在Android上使用它。
如果要从Android事件处理程序启动协程,则应使用当前的Activity作为其协程范围。这样可以确保在销毁活动时取消协程。否则,协程将继续进行,指的是已死的活动。
这是从documentation on CoroutineScope
改编而成的示例,它显示了如何将您的活动用作协程范围:
class MyActivity : AppCompatActivity(), CoroutineScope {
// Sets up the default dispatcher and the root job that we can use to centrally
// cancel all coroutines. We use SupervisorJob to avoid spreading the failure
// of one coroutine to all others.
override val coroutineContext: CoroutineContext =
Dispatchers.Main + SupervisorJob()
override fun onDestroy() {
super.onDestroy()
coroutineContext[Job]!!.cancel()
}
// this.launch picks up coroutineContext for its context:
fun loadDataFromUI() = this.launch {
// Switch to the IO dispatcher to perform blocking IO:
val ioData = withContext(Dispatchers.IO) {
// blocking I/O operations
}
draw(ioData) // use the data from IO to update UI in the main thread
}
}
如果您使用的是ViewModel
,请将其用作范围并从onClear
取消主作业。
如果您是通过后台工作来完成工作,请以JobService
实现为范围,并以onStartJob
和{{ 1}}。
答案 1 :(得分:6)
我的gradle文件中缺少协程的Android部分
实施 “ org.jetbrains.kotlinx:kotlinx-coroutines-android:0.30.0”
一旦有了,Dispatchers.Main就会出现