Kotlin:重写协程的父级工作

时间:2019-02-27 11:33:58

标签: android kotlin kotlin-coroutines

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

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()
    }
}

2 个答案:

答案 0 :(得分:0)

您的第二个示例是正确的。您可以使用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 { ... }

答案 1 :(得分:0)

通过将协程的生命周期与某个UI组件对齐,可以将其称为“结构化并发”。

请参阅以下文档:https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#structured-concurrency-lifecycle-and-coroutine-parent-child-hierarchy

您应该考虑实现自己的作用域并维护一个GlobalScope,而不是使用Job,也可以取消该作用域以取消所有孩子。

这是一个简化的示例:

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 {
          //...
       }
    }
}