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

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

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 小时前
[Android] APK提取器(1.3.7)版本
android
m0_748232641 小时前
mysql的主从配置
android·mysql·adb
秋长愁1 小时前
Android监听应用前台的实现方案解析
android
胖虎12 小时前
2025 新版Android Studio创建Java语言项目
android·java·android studio·创建java项目
JabamiLight3 小时前
Lineageos 22.1(Android 15)Launcer简单调整初始化配置
android·android 15·lineageos 22.1·launcer
敲代码的鱼哇5 小时前
设备唯一ID获取,支持安卓/iOS/鸿蒙Next(uni-device-id)UTS插件
android·ios·uniapp·harmonyos
太空漫步117 小时前
android滑动看新闻
android
KdanMin7 小时前
“让App玩捉迷藏:Android教育平板的‘隐身术’开发实录”
android
韩曙亮7 小时前
【Android】Android 悬浮窗开发 ( 动态权限请求 | 前台服务和通知 | 悬浮窗创建 )
android·service·悬浮窗·服务·前台服务·动态权限·通知通道
双鱼大猫7 小时前
一句话说透Android里面的BufferQueue机制
android·程序员