MutableLiveData: невозможно вызвать setValue в фоновом потоке из Coroutine - PullRequest
0 голосов
/ 14 ноября 2018

Я пытаюсь запустить обновление LiveData из сопрограммы:

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

но я получаю следующую ошибку:

IllegalStateException: невозможно вызвать setValue в фоновом потоке

Есть ли способ заставить его работать с сопрограммами?

Ответы [ 3 ]

0 голосов
/ 14 ноября 2018

Вы можете сделать одно из следующих действий:

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

return AddressList
}

или

fun getAddressesLiveData(): LiveData<List<Address>> {
    AddressList.value = listOf()
    GlobalScope.launch {
        val adresses = getAddressList()
        withContext(Dispatchers.Main) {
            AddressList.value = adresses
        }
    }
    return AddressList
}
0 голосов
/ 15 ноября 2018

Хотя другие отмечают, что в этом случае библиотека предоставляет собственный метод публикации операции в основном потоке, сопрограммы предоставляют общее решение, которое работает независимо от функциональности данной библиотеки.

Первым шагом является прекращение использования GlobalScope для фоновых заданий. Это может привести к утечкам, из-за которых ваша деятельность или запланированная работа, или любая другая единица работы, из которой вы ее вызываете, могут быть уничтожены, и все же ваша работа будет продолжить в фоновом режиме и даже представить свои результаты в основной теме. Вот что гласит официальная документация по GlobalScope:

Код приложения, как правило, должен использовать определяемый приложением CoroutineScope, поэтому использование асинхронного или запуска на экземпляре GlobalScope крайне нежелательно.

Вы должны определить свою собственную область сопрограммы, а ее свойство coroutineContext должно содержать Dispatchers.Main в качестве диспетчера. Кроме того, весь шаблон запуска заданий в вызове функции и возврата LiveData (что по сути является другим видом Future) - не самый удобный способ использования сопрограмм. Вместо этого вы должны иметь

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

и на сайте вызова вы должны launch сопрограмму, в рамках которой вы теперь можете свободно вызывать getAddresses(), как если бы это был метод блокировки, и получать адреса непосредственно в качестве возвращаемого значения.

0 голосов
/ 14 ноября 2018

Я только что понял, что это возможно, используя withContext(Dispatchers.Main){}:

object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
    GlobalScope.launch {
        withContext(Dispatchers.Main){ AddressList.value = getAddressList() }
    }
    return AddressList
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...