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

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

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

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

相关推荐
yuanManGan5 小时前
走进Linux的世界:初识操作系统(Operator System)
android·linux·运维
叶羽西5 小时前
Android15跟踪函数调用关系
android
消失的旧时光-19437 小时前
webView 的canGoBack/goBack 回退栈
android·webview
SHEN_ZIYUAN7 小时前
Flow 责任链模式图解
android
沐怡旸9 小时前
【底层机制】LeakCanary深度解析:从对象监控到内存泄漏分析的完整技术体系
android·面试
又菜又爱coding9 小时前
Android + Flutter打包出来的APK体积太大
android·flutter
LiuYaoheng9 小时前
【Android】Drawable 基础
android·java
Jerry11 小时前
构建 Compose 界面
android
Y多了个想法11 小时前
Linux驱动开发与Android驱动开发
android·linux·驱动开发
2501_9160074714 小时前
从零开始学习iOS App开发:Xcode、Swift和发布到App Store完整教程
android·学习·ios·小程序·uni-app·iphone·xcode