如何在主线程上使用协程GlobalScope?

时间:2018-09-30 20:22:52

标签: android kotlin kotlin-coroutines

我试图在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,但它们都不起作用,我不知道自己在做什么错?我的主线程选项在哪里?

2 个答案:

答案 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就会出现