如何在主线程上使用协程 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
实施作为范围并使用 onStartJob
和 onStopJob
我们使用 onCreate
和onDestroy
以上。
我正在尝试使用 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
实施作为范围并使用 onStartJob
和 onStopJob
我们使用 onCreate
和onDestroy
以上。