我正在尝试从协程触发LiveData的更新:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.value = getAddressList()
}
return AddressList
}
但我得到以下错误:
IllegalStateException:无法在后台线程上调用setValue
有没有一种方法可以让它与协程一起工作?
9条答案
按热度按时间p1tboqfb1#
使用
liveData.postValue(value)
代替liveData.value = value
。它称为异步。来自文件:
postValue-将任务发布到主线程,设置给定值。
t5zmwmid2#
您可以执行以下操作之一:
或
cygmwpex3#
我刚刚发现使用
withContext(Dispatchers.Main){}
是可能的:zpf6vheq4#
尽管其他人指出,在这种情况下,库提供了自己的方法来将操作发布到主线程,但协程提供了一种通用的解决方案,无论给定库的功能如何。
第一步是停止对后台作业使用
GlobalScope
,这样做将导致泄漏,您的Activity或计划作业或您从中调用的任何工作单元可能会被破坏,但您的作业将继续在后台运行,甚至将其结果提交给主线程。以下是official documentation onGlobalScope
的声明:应用程序代码通常应该使用应用程序定义的CoroutineScope,在GlobalScope示例上使用async或launch是非常不鼓励的。
您应该定义自己的协程作用域,其
coroutineContext
属性应该包含Dispatchers.Main
作为分派器。此外,在函数调用中启动作业并返回LiveData
(基本上是另一种Future
)的整个模式并不是使用协程的最方便方式。相反,您应该具有在调用站点,您应该
launch
一个协程,在其中您现在可以自由地调用getAddresses()
,就好像它是一个阻塞方法一样,并直接获取地址作为返回值。velaa5lx5#
如果你想使用协程来更新UI,有两种方法可以实现
GlobalScope.launch(Dispatchers.Main):
如果你想在后台完成一些工作,但之后你想更新UI,这可以通过以下方式实现:
withContext(Dispatchers.Main)
nzrxty8p6#
在我的例子中,我不得不将Dispatchers.Main添加到启动参数中,它工作得很好:
x6h2sr287#
当我在runBlockingTest中调用一个测试用例的协程时,我就遇到了这个错误
我通过添加instantExecutorRule作为类成员来修复它
brgchamk8#
下面的代码为我从线程更新livedata工作:
hpcdzsge9#
来自@Amir Hossein Ghasemi的答案很好。只是为了补充它。
liveData.value = value用于只在主线程上更新一个LiveData的值。通常用于RxJava
而**liveData.postValue(value)**则可以从任何线程调用,包括主线程和后台线程(异步)