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

How to use coroutines GlobalScope on the main thread?

我正在尝试使用 0.30.0 中的最新协程,但无法弄清楚如何使用新的范围。在原始协程中,我可以使用 UI 或 CommonPool 设置上下文,一切正常。

现在我尝试在我的 ViewModel 中使用 GlobalScope,同时从房间数据库读取数据,然后我想将返回的值分配给我的 LiveData 对象。

当我尝试设置 LiveData 值时出现以下错误

java.lang.IllegalStateException: Cannot invoke setValue on a background thread

fun getContact() {
        GlobalScope.launch {
            val contact = contacts.getContact() // suspended function
            withContext(Dispatchers.Default) { phoneContact.value = contact }
        }
    }

我只看到调度程序的 Default、Unconfined 和 IO,其中 none 有效,我不知道我做错了什么?我的主线程选项在哪里?

我在 gradle 文件

中遗漏了协程的 Android 部分

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.30.0"

一旦我有了那个,Dispatchers.Main就出现了

您通过添加依赖项解决了眼前的问题,但让我在您对 GlobalScope.

的用法上添加注释

在生产代码中使用 GlobalScope 是一种反模式。出于类似的原因,它在那里 runBlocking,使快速实验变得容易。由于应用程序组件的复杂生命周期,您应该特别避免在 Android 上使用它。

如果您从 Android 事件处理程序启动协程,则应使用当前 Activity 作为其协程范围。这将确保您的协程在 activity 被销毁时被取消。没有它协程将继续,指的是现在已经死了 activity.

这是一个改编自 documentation on CoroutineScope 的示例,它展示了如何使用您的 activity 作为协程范围:

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 实施作为范围并使用 onStartJobonStopJob 我们使用 onCreateonDestroy 以上。