为了活动小家电-CoroutineScope取消处理(一)

265 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的12天,点击查看活动详情

使用 CoroutineScope

使用GlobalScope的时候,根据情况可能会有所不同,但是在上一篇文章中发现,在使用需要长时间运行的程序时需要谨慎,一定要在不影响内存的情况下使用问题和应用程序的操作。

在本文中,我们将探索 CoroutineScope

看文档的话,介绍了可以在Android中使用的MainScope()部分,首先来看看示例。

class TestClass {
    // 测试类的作用域
    val scope = MainScope() // the scope of MyUIClass

    // 类销毁的时候进行作用域的取消
    fun destroy() {
        scope.cancel() 
    }

    /*
     * 如果此实例被销毁或该方法中任何启动的协程抛出异常,则所有嵌套协程都将被取消。
     */
    fun doSomething() = scope.launch { 
        // 这样启动在主线程中
        }
    }

如果你看这个MainScope的内部代码,你可以看到它使用的是CoroutineScope,并且是添加了Android相关的代码。

@Suppress("FunctionName")
public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)

继续往下查看,MainScope将使用一个继承 CoroutineScope 并仅注入可以使用它的上下文的通用代码。

作为参考,此代码是内部的,不能在外部使用。

internal class ContextScope(context: CoroutineContext) : CoroutineScope {
    override val coroutineContext: CoroutineContext = context
    
    override fun toString(): String = "CoroutineScope(coroutineContext=$coroutineContext)"
}

如果你直接继承 CoroutineScope 而不是 MainScope,你应该如下工作。

class TestActivity : AppCompatActivity(), CoroutineScope {

    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + SupervisorJob()

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

最后,您必须完成取消取消的工作。

无条件调用取消并不意味着终止

让我们看一下这段代码并进行预测。

class CoroutineCancel {

    @Test
    fun testCancel() = runBlocking {
        val job = SupervisorJob()
        CoroutineScope(Dispatchers.IO).launch {
            while (isActive) {
                println("Job存活着")
                delay(1)
            }
        }

        delay(50)
        job.cancel()
        delay(500)
    }
}

注意:因为这是一个测试代码,所以它会在 500 毫秒后结束。

此代码中的 CoroutineScope 不会终止。

  • while 循环不停。
  • 退出失败,因为 CoroutineScope 里面没有调用 exit 的代码。

首先,让我们将这段代码中的 while 语句更改为单独的挂起函数。

private suspend fun suspendLoop() = withContext(Dispatchers.IO) {
    while (isActive) {
        println("Job存活着")
        delay(1)
    }
}

这也与它仅在 500ms 后终止相同。

然后,你需要修改它,让它可以终止,如果你添加一个作业如下,它会自然终止。

val job = SupervisorJob()
CoroutineScope(Dispatchers.IO + job).launch {
    suspendLoop()
}

为了活动小家电,下篇继续搞!