【问题标题】:What is the correct way of using Anko Coroutines extensions?使用 Anko Coroutines 扩展的正确方法是什么?
【发布时间】:2018-05-07 18:56:54
【问题描述】:

所以我正在将一个示例应用程序从 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 对象。但我想知道 Anko Coroutines 的 asReference() 函数是否也一样,不需要保存 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())
        }
    }
}

我可以在 onDestroy() 方法中调用 job.cancel() 时取消协程,但要使其正常工作,我必须检查作业是否处于活动状态,并且转换为 if/else 和返回或不数据.有没有更好的方法在作业被取消时返回?

【问题讨论】:

    标签: android kotlin kotlinx.coroutines anko


    【解决方案1】:

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

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

    launch 来自 kotlinx.coroutines 的协程构建器返回一个 Job 实例。这是一个例子:

    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(launch) Job 对子协程(async) 的引用来实现这一点。

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

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

    【讨论】:

    • 谢谢!真的很棒的答案!明天试试。没有抓住关于取消子协程的 2 点。无论如何,真的很棒的答案。如果取消是合作的,则无法取消 HTTP 连接,对吗?
    • 谢谢。 coroutines 对您的情况下的取消含义一无所知。它只是发送一个信号,您将通过检查 isActive 获得它(请参阅上面链接中的取消示例)。对于 http Retrofit 有取消机制。
    • 你能看看我的原帖吗?用你的 cmets 更新。
    • @NicolasJafelle 您的问题将变得大而多话题。最好问一个新问题。
    猜你喜欢
    • 2017-12-01
    • 2017-09-14
    • 1970-01-01
    • 2020-08-18
    • 1970-01-01
    • 2020-02-13
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    相关资源
    最近更新 更多