协程学习(五)协程作用域的传播与协程取消后的状态变化

协程作用域的创博是子协程默认使用的是父协程的作用域,这么做的好处能更好的管理所有子协程,下面再举个例子

scss 复制代码
    @JvmStatic
    fun main(a:Array<String>) {
        runBlocking {
            launch {
                delay(1000)
                println("-------end runBlocking launch--------")
            }

            launch {
                delay(1500)
                println("-------end runBlocking with new Dispatchers launch--------")
            }
        }
    }
-------end runBlocking launch--------
-------end runBlocking with new Dispatchers launch--------

Process finished with exit code 0    

在这段代码中我们使用 runBlocking 创建了一个 协程,同时在 runBlocking 中使用launch 创建了2个子协程,

从这个例子可以看出来不管子协程刮起了多久,父协程都会等待子协程执行完成,

那么什么是协程作用域呢

这段代码中的 CoroutineScope 就是协程作用域,那么如果我们在 runBlocking 中创建一个新的协程作用域,看看他的表现又是如何

scss 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking {
        launch {
            delay(1000)
            println("-------end runBlocking launch--------")
        }

        launch {
            delay(1500)
            println("-------end runBlocking with new Dispatchers launch--------")
        }

        GlobalScope.launch{
            delay(2000)
            println("-------end new CoroutineScope launch--------")
        }

    }
}

结果:
-------end runBlocking launch--------
-------end runBlocking with new Dispatchers launch--------

Process finished with exit code 0

可以看到如果使用新的作用域的子协程如果耗时是最长的,那么外部协程是不会等待这个协程的

为什么说 GlobalScope.launch 是一个新的协程作用域 而上面的 launch 则不是呢,我们先来看一下 runBlocking 方法

kotlin 复制代码
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {
...省略
}

由于我们使用 lambda 表达式 runBlocking 就变成了上面的样子,下面我们使用正常的用法来写这个 runBlocking

kotlin 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking(block = {
        launch {
            delay(1000)
            println("-------end runBlocking launch--------")
        }

        launch {
            delay(1500)
            println("-------end runBlocking with new Dispatchers launch--------")
        }
    })
}

可以看到 runBlocking 大括号内的方法就是 block 方法,而block 方法是 CoroutineScope 的匿名扩展方法,最后我们 runBlocking 的协程作用域就是我们常见的这个 CoroutineScope, 下面第一个 launch 方法又如何解释呢

kotlin 复制代码
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

launch 方法是 CoroutineScope 的扩张方法,只要我们能获取到 CoroutineScope ,就能直接使用

由于这个方法是 CoroutineScope 的匿名扩展方法,所以他可以用 CoroutineScope 内的所有方法,再将 launche 方法前面加上this ,就是他的原始模样,

kotlin 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking(block = {
        this.launch {
            delay(1000)
            println("-------end runBlocking launch--------")
        }

        this.launch {
            delay(1500)
            println("-------end runBlocking with new Dispatchers launch--------")
        }
    })
}

所以在不重新指定新的作用域的情况下, 子协程默认使用的是父协程的作用域

说完了协程作用域的传播再来看看取消后 job 状态的变化

先来看一下协程启动前与协程执行完成后的状态变化

kotlin 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking(block = {
        var job= this.launch {
            delay(1000)
            println("-------end runBlocking launch--------")
        }
        println("job isActive:${job.isActive}    isCancelled:${job.isCancelled}   isCompleted:${job.isCompleted}")
        job.join()
        println("job isActive:${job.isActive}    isCancelled:${job.isCancelled}   isCompleted:${job.isCompleted}")
    })
}
结果:
job isActive:true    isCancelled:false   isCompleted:false
-------end runBlocking launch--------
job isActive:false    isCancelled:false   isCompleted:true

Process finished with exit code 0

各个状态看起来都比较正常,我们再看一下子协程未启动前取消他的状态变化

kotlin 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking(block = {
        var job= this.launch {
            delay(1000)
            println("-------end runBlocking launch--------")
        }
        job.cancel()
        println("job isActive:${job.isActive}    isCancelled:${job.isCancelled}   isCompleted:${job.isCompleted}")
        delay(2000)
        println("job isActive:${job.isActive}    isCancelled:${job.isCancelled}   isCompleted:${job.isCompleted}")
    })
}
结果:
job isActive:false    isCancelled:true   isCompleted:false
job isActive:false    isCancelled:true   isCompleted:true

Process finished with exit code 0

在协程没有启动前就取消了协程,看到子协程的变化由原来的活跃状态变为了 取消状态,但是等到子协程挂起恢复后的时间节点后,子协程又变为了 已完成同时也是已取消的状态,这个就比较有意思了

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui