Anko协程扩展的正确使用方法是什么?

What is the correct way of using Anko Coroutines extensions?

所以我正在将一个示例应用程序从 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 基础 class 有一个 CompositeSubscription 并且在 onDestroy 的片段或 activity 方法简单取消订阅并清除 CompositeSubscription 对象。但是我想知道 Anko Coroutines 中的 asReference() 函数是否做同样的事情并且不需要保存 Deferred<T> 的列表然后迭代它并一个一个地取消。

顺便说一句,如果我添加一个 Thread.sleep(5000) 来模拟一个大事务并销毁片段,我可以在 logcat 中看到 HTTP 响应,即使片段不是 visible/destroyed 而与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())
        }
    }
}

我可以在 onDestroy() 方法中调用 job.cancel() 时取消协程,但要使其正常工作,我必须检查该作业是否处于活动状态并将其转化为 if/else 和一个 return 或不是数据。当作业被取消时,有什么更好的方法来 return 东西吗?

正如您在 asReference() 源代码中看到的那样,它只不过是一个弱引用和调用方法来获取在收集对象时抛出 CancellationException 的引用。它不执行任何取消操作。只是知道收集的对象

因此您需要保留对 Job 或其子类型的引用才能取消操作。

launch 来自 kotlinx.coroutines returns 作业实例的协程构建器。这是一个例子:

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-当结果类型不重要时,可以使用launch代替async

2- 要在子协程中取消,您必须创建 parent/child 作业层次结构。我通过了 parent(launch) Job 对 child coroutine(async) 的引用来实现这一点。

3- 因为 取消是合作的 取消实现必须异步完成(参见示例 here)。

3- job.cancel() 用于 onDestroy 取消作业,它是子异步。这可以在 Presenter 中以 MVP 模式完成。