Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin MutableLiveData:无法从协同例程在后台线程上调用setValue_Kotlin_Android Livedata_Kotlin Coroutines - Fatal编程技术网

Kotlin MutableLiveData:无法从协同例程在后台线程上调用setValue

Kotlin MutableLiveData:无法从协同例程在后台线程上调用setValue,kotlin,android-livedata,kotlin-coroutines,Kotlin,Android Livedata,Kotlin Coroutines,我正在尝试从协同程序触发LiveData更新: object AddressList: MutableLiveData<List<Address>>() fun getAddressesLiveData(): LiveData<List<Address>> { AddressList.value = listOf() GlobalScope.launch { AddressList.value = getAddres

我正在尝试从协同程序触发LiveData更新:

object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
    AddressList.value = listOf()
    GlobalScope.launch {
        AddressList.value = getAddressList()
    }
    return AddressList
}
对象地址列表:MutableLiveData()
fun getAddressesLiveData():LiveData{
AddressList.value=listOf()
环球镜发射{
AddressList.value=getAddressList()
}
回信地址表
}
但我得到了以下错误:

IllegalStateException:无法在后台线程上调用setValue


有没有一种方法可以让它与协同程序一起工作?

我刚刚发现,通过使用
和上下文(Dispatchers.Main){}
是可能的:

object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
    GlobalScope.launch {
        withContext(Dispatchers.Main){ AddressList.value = getAddressList() }
    }
    return AddressList
}
对象地址列表:MutableLiveData()
fun getAddressesLiveData():LiveData{
环球镜发射{
withContext(Dispatchers.Main){AddressList.value=getAddressList()}
}
回信地址表
}

您可以执行以下操作之一:

object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
    AddressList.value = listOf()
    GlobalScope.launch {
        AddressList.postValue(getAddressList())
    }

return AddressList
}
对象地址列表:MutableLiveData()
fun getAddressesLiveData():LiveData{
AddressList.value=listOf()
环球镜发射{
AddressList.postValue(getAddressList())
}
回信地址表
}

fun getAddressesLiveData():LiveData{
AddressList.value=listOf()
环球镜发射{
val address=getAddressList()
withContext(Dispatchers.Main){
AddressList.value=地址
}
}
回信地址表
}

尽管其他人已经指出,在这种情况下,库提供了自己的方法将操作发布到主线程,但协程提供了一种通用的解决方案,无论给定库的功能如何,都能正常工作

第一步是停止在后台作业中使用
GlobalScope
,这样做会导致泄漏,您的活动、计划作业或您调用它的任何工作单元可能会被破坏,而您的作业将在后台继续,甚至将其结果提交给主线程。以下是各州的情况:

应用程序代码通常应该使用应用程序定义的CoroutineScope,强烈建议在GlobalScope实例上使用async或launch

您应该定义自己的协同程序作用域,其
coroutineContext
属性应该包含
Dispatchers.Main
作为调度器。此外,在函数调用中启动作业并返回
LiveData
(这基本上是另一种
未来
)的整个模式并不是使用协同路由的最方便方式。相反,你应该这样做

suspend fun getAddresses() = withContext(Dispatchers.Default) { getAddressList() }

在调用站点,您应该
启动
一个协同程序,您现在可以在其中自由调用
getAddresses()
,就像它是一个阻塞方法一样,并直接获取地址作为返回值。

在我的例子中,我必须在启动参数中添加Dispatchers.Main,效果很好:

 val job = GlobalScope.launch(Dispatchers.Main) {
                    delay(1500)
                    search(query)
                }

如果您想通过使用协同程序更新UI,有两种方法可以实现这一点

GlobalScope.launch(Dispatchers.Main):

GlobalScope.launch(Dispatchers.Main) {
    delay(1000)     // 1 sec delay
    // call to UI thread
}
如果您希望在后台完成一些工作,但之后您希望更新UI,可以通过以下方式实现:

withContext(Dispatchers.Main)


使用
liveData.postValue(value)
而不是
liveData.value=value
。它被称为异步

发件人:

postValue-将任务发布到主线程以设置给定值


你不想使用postValue有什么原因吗?@RedDeckWins。不,我只是没有考虑到这一点,但这绝对是从协同程序更新可变LiveData的方法。不要在
withContext(Dispatchers.Main)
块中调用
getAddressList()
,因为这将在主线程上运行。在外部调用它,以便它由
分派器正确分派。默认设置为
并仅在主线程上使用结果您只需返回繁重的任务以在UI线程中运行谢谢@kikey实际上,我认为这是完美的
postValue()
使用场景。不需要强制主线程上下文。
GlobalScope.launch(Dispatchers.Main) {
    delay(1000)     // 1 sec delay
    // call to UI thread
}
GlobalScope.launch {
    delay(1000)     // 1 sec delay

    // do some background task

    withContext(Dispatchers.Main) {
            // call to UI thread
    }
}