Сопрограммы Kotlin - Являются ли вложенные сопрограммы правильным способом обработки различных потоков в одной сопрограмме? - PullRequest
0 голосов
/ 04 мая 2018

Я пробую сопрограммы вместо RxJava на основных сетевых вызовах в первый раз, чтобы увидеть, как это происходит, и сталкиваюсь с некоторыми проблемами с запаздыванием / многопоточностью

В приведенном ниже коде я выполняю сетевой вызов userRepo.Login() и, если возникает исключение, я показываю сообщение об ошибке и останавливаю анимацию прогресса, которую я запустил в начале функции.

Если я оставляю все в CommonPool (или не добавляю пул), он вылетает, говоря, что анимация должна выполняться в луперном потоке, если происходит исключение. В других случаях я получал сообщения о том, что это должно быть сделано и в потоке пользовательского интерфейса, та же проблема, другие требования к потоку.

Я не могу запустить всю сопрограмму в потоке пользовательского интерфейса, потому что вызов входа в систему блокируется, поскольку он находится в потоке пользовательского интерфейса и портит мою анимацию (что имеет смысл).

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

Это правильный способ сделать что-то или я что-то упустил?

override fun loginButtonPressed(email: String, password: String) {

    view.showSignInProgressAnimation()

    launch(CommonPool) {
        try { 
            val user = userRepo.login(email, password)

            if (user != null) {
                view.launchMainActivity()
            }

        } catch (exception: AuthException) {
            launch(UI) {
                view.showErrorMessage(exception.message, exception.code)
                view.stopSignInProgressAnimation()
            }
        }
    }
}

1 Ответ

0 голосов
/ 04 мая 2018

Вы должны начать с противоположного конца: запустить сопрограмму на основе пользовательского интерфейса, из которой вы переносите тяжелые операции во внешний пул. Инструмент выбора - withContext():

override fun loginButtonPressed(email: String, password: String) {
    view.showSignInProgressAnimation()
    // assuming `this` is a CoroutineScope with dispatcher = Main...
    this.launch {
        try {
            val user = withContext(IO) { 
                userRepo.login(email, password) 
            }
            if (user != null) {
                view.launchMainActivity()
            }
        } catch (exception: AuthException) {
            view.showErrorMessage(exception.message, exception.code)
            view.stopSignInProgressAnimation()
        }
    }
}

Таким образом, вы сохраняете свою естественную модель программирования Android, которая предполагает поток с графическим интерфейсом.

...