Как использовать сопрограммы GlobalScope в основном потоке? - PullRequest
0 голосов
/ 30 сентября 2018

Я пытаюсь использовать последние сопрограммы в 0.30.0 и не могу понять, как использовать новую область видимости.В исходных сопрограммах я мог установить контекст с помощью пользовательского интерфейса или CommonPool, и все работало правильно.

Теперь я пытаюсь использовать GlobalScope в моей модели представления при чтении из базы данных комнаты, а затем хочу назначитьзначение, возвращенное моему объекту LiveData.

При попытке установить значение LiveData

java.lang.IllegalStateException возникает следующая ошибка: не удается вызвать setValue в фоновом потоке

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

Я вижу только Диспетчеры по умолчанию, Неограниченный и IO, и ни один из них не работает, я не могу понять, что я делаю неправильно?Где мой вариант для главной темы?

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

Вы решили свою непосредственную проблему, добавив зависимость, но позвольте мне добавить примечание о вашем использовании GlobalScope.

Использование GlobalScope в рабочем коде является антипаттерном.Это делается по тем же причинам, что и runBlocking, чтобы облегчить проведение быстрых экспериментов.Вам особенно следует избегать этого на Android из-за сложного жизненного цикла компонентов приложения.

Если вы запускаете сопрограмму из обработчика событий Android, вы должны использовать текущую активность в качестве ее области сопрограммы.Это гарантирует, что ваша сопрограмма будет отменена, когда активность будет уничтожена.Без этого сопрограмма продолжится, ссылаясь на уже мертвую активность.

Вот пример, адаптированный из документации по CoroutineScope, он показывает, как использовать вашу деятельность в качестве сопрограммы.область действия:

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 сентября 2018

Мне не хватало части сопрограмм для Android в моем файле gradle

реализация "org.jetbrains.kotlinx: kotlinx-coroutines-android: 0.30.0"

Как только у меня это появилось, появились Диспетчеры.

...