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

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

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

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

相关推荐
&岁月不待人&4 小时前
⏺ Android 录屏缩放异常排查:Pixel 3 XL 上的完美风暴
android
a3158238064 小时前
Android 大图显示策略优化显示(一)
android·算法·图片加载·大图片
tangweiguo030519874 小时前
从零开始:在 Windows 上使用命令行编译 Android .so 动态库(NDK + CMake + Ninja)
android
阿波罗尼亚4 小时前
Tcp SSE Utils
android·java·tcp/ip
知行合一。。。8 小时前
Python--03--函数入门
android·数据库·python
大、男人9 小时前
python之contextmanager
android·python·adb
不法11 小时前
java查看安卓证书信息
android
儿歌八万首11 小时前
Jetpack Compose 动画实战:让你的 UI 动起来
android·kotlin·动画·compose
千里马学框架11 小时前
如何改进车载三分屏SplitScreen启动交互方式?
android·智能手机·分屏·aaos·安卓framework开发·车载开发·3分屏
REDcker13 小时前
Android WebView 版本升级方案详解
android·音视频·实时音视频·webview·js·编解码