【问题标题】:Kotlin: Override parent job of coroutineKotlin:覆盖协程的父作业
【发布时间】:2019-02-27 11:33:57
【问题描述】:

我正在尝试将以下功能迁移到Kotlin 1.3 的新Coroutine

fun launchUI(strategy: CancelStrategy, block: suspend CoroutineScope.() -> Unit): Job {
    return launch(context = UI, parent = strategy.jobs, block = block)
}

但是新的GlobalScope.launch 函数没有parent 参数。文档说:

父作业也继承自 CoroutineScope,但它 也可以用相应的coroutineContext 元素覆盖。

但我不知道如何覆盖父作业。我现在已经这样实现了,但我不确定它是否会以同样的方式工作:

fun launchUI(strategy: CancelStrategy, block: suspend CoroutineScope.() -> Unit): Job {
    val job = GlobalScope.launch(context = Dispatchers.Main, block = block)
    strategy.jobs.invokeOnCompletion {
        job.cancel()
    }
    return job
}

谁能帮帮我?

更新:

class CancelStrategy(owner: LifecycleOwner, val jobs: Job) : LifecycleObserver {

    init {
        owner.lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        jobs.cancel()
    }
}

【问题讨论】:

  • 什么是CancelStrategy

标签: android kotlin kotlin-coroutines


【解决方案1】:

你的第二个例子是正确的。您可以使用plus 将作业添加为新协程的父作业。

fun launchUI(strategy: CancelStrategy, block: suspend CoroutineScope.() -> Unit): Job {
    return GlobalScope.launch(context = Dispatchers.Main + strategy.jobs, block = block)
}

但不鼓励使用GlobalScope。最好创建一个自己的CoroutineScope。您的 CancelStrategy 看起来是个不错的候选人。

class CancelStrategy(owner: LifecycleOwner, val jobs: Job) : LifecycleObserver, CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + jobs

    init {
        owner.lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        jobs.cancel()
    }
}

现在你可以像这样启动你的协程了:

cancelStrategy.launch { ... }

【讨论】:

    【解决方案2】:

    通过将协程的生命周期与某些 UI 组件保持一致,您想要的称为“结构化并发”。

    查看此文档:https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#structured-concurrency-lifecycle-and-coroutine-parent-child-hierarchy

    您应该考虑实现自己的范围并维护Job 他们,而不是使用GlobalScope,您也可以取消它以取消所有孩子。

    这是一个简化的例子:

    class Activity : CoroutineScope {
        lateinit var job: Job //tied to lifecycle of Activity
        fun create() {
            job = Job()
        }
    
        fun destroy() {
            //will cancel all child jobs as well
            println("cancel $job and all ${job.children.toList().size} children")
            job.cancel()
        }
    
        override val coroutineContext: CoroutineContext
            get() = Dispatchers.Default + job + CoroutineName("MyActivityContext")
    
        fun doSomething() {
           //we launch in the outer scope of Activity
           launch {
              //...
           }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-23
      • 1970-01-01
      相关资源
      最近更新 更多