Как правильно использовать расширения Anko Coroutines?

Итак, я переношу пример приложения с RxJava на Kotlin / Anko Corountines, и мне интересно, делаю ли я лучший (первый) подход к нему:

fun getPopulationList() {
    val ref = asReference()

    async(UI) {
        try {
            ref().setCurrentState(ViewState.State.LOADING)
            val background = bg {
                repository.populationResponse().execute().body()
            }

            ref().let {
                it.response = background.await()
                it.mvpView?.onGetData(it.response)
                it.setCurrentState(ViewState.State.FINISH)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            ref().mvpView?.onError(e)
        }
    }
}

Я использую архитектуру MVP, в которой мой Presenter базовый класс имеет CompositeSubscription, а в onDestroy методе фрагмента или действия просто отписывайтесь и очищайте объект CompositeSubscription. Но мне интересно, делает ли функция asReference() из Anko Coroutines то же самое, и нет необходимости сохранять список Deferred<T>, а затем повторять его и отменять один за другим.

Кстати, если я добавлю Thread.sleep(5000) для имитации большой транзакции и уничтожения фрагмента, который я вижу в logcat, HTTP-ответ даже после того, как фрагмент не виден / уничтожен, в то время как с RxJava не происходит, поэтому я думаю, что я не использую должным образом.

ОБНОВЛЕНИЕ

 fun getPopulationList() {
    val ref = asReference()

    job = launch(UI) {

        try {
            ref().setCurrentState(ViewState.LOADING)
            val background = bg {
                Thread.sleep(5000) //simulate heavy IO

                if (isActive) {
                    repository.populationResponse().execute().body()
                } else {
                    return@bg null
                }
            }

            ref().let {
                it.response = background.await()
                it.mvpView?.onGetData(it.response)
                it.setCurrentState(ViewState.FINISH)
            }
        } catch (e: Exception) {
            RestHttpExceptionHandler().handle(UI, e, ref())
        }
    }
}

Я могу отменить сопрограмму при вызове метода job.cancel() в onDestroy(), но чтобы он заработал, я должен проверить, активно ли задание, и это преобразовать в if / else и данные return or not. Есть ли лучший способ вернуть что-нибудь, когда работа была отменена?


person Nicolas Jafelle    schedule 23.11.2017    source источник


Ответы (1)


Как вы можете видеть в asReference () это не что иное, как слабая ссылка и метод вызова для получения ссылки, которая выдает CancellationException при сборе объекта. он не делает ничего для отмены операции. просто осведомлен о собранном объекте.

поэтому вам нужно сохранить ссылку на Job или его подтип для отмены операции.

launch построитель сопрограмм из kotlinx.coroutines возвращает экземпляр задания. вот пример:

private lateinit var job: Job

private fun startCoroutines() {
    val ref = asReference()
    job = launch(UI) {
        try {
            val deferred = async(parent = coroutineContext[Job]) {
                    //do some work
                    result//return
            }

            ref().setData(deferred.await())
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

}


override fun onDestroy() {
    super.onDestroy()
    job.cancel()
}

Примечания:

1 - когда тип результата не важен, вместо async можно использовать launch.

2- чтобы выполнить отмену в дочерних сопрограммах, вы должны создать иерархию родительских / дочерних заданий. Я передал родительскую (launch) Job ссылку на дочернюю сопрограмму (асинхронную), чтобы добиться этого.

3- поскольку отмена возможна, реализация отмены должна выполняться в асинхронном режиме (см. Примеры здесь).

3- job.cancel() используется в onDestroy, отменяет задание и является дочерним асинхронным. это можно сделать в Presenter в шаблоне MVP.

person David    schedule 29.03.2018
comment
Спасибо! Действительно отличный ответ! Завтра попробую. Не понял 2 пункта об отмене дочерних сопрограмм. В любом случае действительно отличный ответ. Если отмена осуществляется кооперативно, HTTP-соединение не может быть отменено, верно? - person Nicolas Jafelle; 29.03.2018
comment
Спасибо. сопрограммы ничего не знают о том, что означает отмену в вашем случае. Он просто отправляет сигнал, и вы получите его с проверкой isActive (см. Примеры отмены в ссылке выше). Для http Retrofit есть механизм отмены. - person David; 29.03.2018
comment
Вы можете проверить мой исходный пост? обновлен вашими комментариями. - person Nicolas Jafelle; 03.04.2018
comment
@NicolasJafelle, ваш вопрос станет большим и многогранным. лучше задать новый вопрос. - person David; 18.04.2018