美文网首页
kotlin协程二

kotlin协程二

作者: crossroads | 来源:发表于2021-01-12 20:43 被阅读0次

    前言

    翻译自 进阶Part 1: Coroutines

    CoroutineScope

    一个CoroutineScope跟踪任意一个用launch或async创建的协程(Coroutines),运行中的协程可以在任何时间点用scope.cancel()取消。
    当你在APP的一个特定层想要开始并控制协程的生命周期的时候应该创建一个CoroutineScope。这里有一些KTX库,已经在某些生命周期类中提供了CoroutineScope,例如viewmodelScope和lifecyclescope。
    创建CoroutineScope需要传一个CoroutineContext类型的参数,例如如下代码

        val scope = CoroutineScope(Dispatchers.Default)
            val job = scope.launch {
                // 这里创建协程
            }
    

    作者这里是这样创建的

      val scope = CoroutineScope(Job() + Dispatchers.Main)
            val job = scope.launch {
                // 这里创建协程
            }
    

    这个+号的作用后续会讲。这也是传入一个CoroutineContext类型的参数创建CoroutineScope。

    Job

    Job是协程的句柄,对于每一个通过launch或者async创建的协程,都会返回一个job对象,唯一指定协程病管理它的生命周期。如上面的代码,我们也可以将job传给CoroutineScope掌控其生命周期。

    CoroutineContext

    CoroutineContext是一套定义协程行为的元素。它构成于:

    1. job -控制协程的生命周期
    2. CoroutineDispatcher - 将工作分配到合适的线程
    3. CoroutineName - 协程名字,debug很有用
    4. CoroutineExceptionHandler - 处理未捕获的异常,在后续会讲解。
      新协程的CoroutineContext是什么?我们已经知道将创建一个新的job对象使我们管理协程的生命周期,剩下的几个元素会从CoroutineContext的父级(另一个协程或者在其创建的CoroutineScope)中继承。
      由于CoroutineScope可以创建协程,并且可以在一个协程中创建更多协程,因此一个隐藏的任务层级将会被创建,下面举个例子
    val scope = CoroutineScope(Job() + Dispatchers.Main)
    val job = scope.launch {
        // 创建新的协程, CoroutineScope作为父级
        val result = async {
            // 创建新的协程,通过launch创建的协程作为父级
        }.await()
    }
    

    协程在任务层次结构中执行,CoroutineContext是继承的,父级可以来自CoroutineScope或另一个协程,继承的根节点一般是CoroutineScope。
    大白话就是,每一个协程都有一套定义其行为的元素,这些元素由上面四个组成,总称为CoroutineContext 。新协程的这套元素来自其他协程或者创建出来的CoroutineScope 。协程中可以创建协程,这套元素也是继承的,由父级传下来的,一般根节点是创建出来的CoroutineScope。

    Job lifecycle

    一个job贯穿一系列状态:new、active、completing、completed、cancelling和cancelled 。我们可以通过isActive 、isCancelled 和 isCompleted得到job的状态属性。


    job生命周期

    父CoroutineContext 释义

    在任务继承体系中,任意一个协程都有一个父级可以是一个CoroutineScope 或者是其他的协程。然而,协程的最终父CoroutineContext可以不同于父协程的CoroutineContext,
    计算规则如下:
    Parent context = Defaults + inherited CoroutineContext + arguments

    1. Defaults:一些元素有默认值,例如CoroutineDispatcher的默认值是Dispatchers.Default ,CoroutineName的默认值是“ coroutine”
    2. inherited CoroutineContext 是创建它的CoroutineScope或协程的CoroutineContext
    3. arguments 在构建协程的传的参数将优先于继承的那些元素
      注意: CoroutineContexts可以通过+号合并。由于CoroutineContext是一系列元素,创建一个新的CoroutineContext,+号右边的元素会覆盖加好左边的元素。
      例如:(Dispatchers.Main, “name”) + (Dispatchers.IO) = (Dispatchers.IO, “name”)。
      每个通过CoroutineScope发起的协程,CoroutineContext至少会有这些元素。协程名字之所以是灰色的是因为来自默认值
      我们已经知道一个新协程的父CoroutineContext是什么,那么新协程自己的真正CoroutineContext是:
      New coroutine context = parent CoroutineContext + Job()
      如果用上面的图片中的scope创建一个新的协程,例如
    val job = scope.launch(Dispatchers.IO) {
        // new coroutine
    }
    

    这个协程的父CoroutineContext和它真正的CoroutineContext是什么呢?如下


    父CoroutineContext和新协程的CoroutineContext的job永远都不会是同一个实例,因为新协程总会得到一个job的新实例

    父CoroutineContext的真正结果之所以有Dispatchers.IO而不是scope的CoroutineDispatcher,是因为被创建协程时传的Dispatchers.IO这个参数重写了。另外,检查父CoroutineContext的job是scope的job实例(红色),新协程的CoroutineContext的job则是新的实例(绿色)。
    后续会学到CoroutineScope的CoroutineContext可以是不同的job实现类,例如SupervisorJob, 这将改变CoroutineScope处理异常的方式。因此,使用该scope创建的协程,父级job将会是SupervisorJob。但是,当协程的父级是另一个协程时,父级Job始终为Job类型。

    后记

    至此,part 1 正式翻译完了, 望指正o( ̄︶ ̄)o。

    相关文章

      网友评论

          本文标题:kotlin协程二

          本文链接:https://www.haomeiwen.com/subject/fkltaktx.html