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

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

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

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

相关推荐
姑苏风1 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
数据猎手小k4 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
你的小105 小时前
JavaWeb项目-----博客系统
android
风和先行5 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.6 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰7 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶7 小时前
Android——网络请求
android
干一行,爱一行7 小时前
android camera data -> surface 显示
android
断墨先生7 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员9 小时前
PHP常量
android·ide·android studio