kotlin协程问题

一:拦截器可以有多个吗

不可以,因为CoroutineContext在组合在一起的时候,是从左往右累加的,具有相同Key值的Element,左边的会丢弃。而拦截都继承的

ContinuationInterceptor

它内部代码是这样的

public interface ContinuationInterceptor : CoroutineContext.Element {

companion object Key : CoroutineContext.Key<ContinuationInterceptor>
。。。。
}

也就是说拦截器的Key值是相同的。

 二:协程的官方解释

协程(英语:coroutine)是计算机程序的一类组件,推广了协作式多任务子例程,允许执行被挂起与被恢复。

协作式多任务和多线程中的抢占式多任务相对,子例程就是方法或函数。那么是不是可以说,协程就是这样一个框架: 控制若干个方法合作式的执行。

三:job的本质

Job对象具有lifecycle生命周期属性, 协程之间具有父子关系,父协程在所有子协程完成之后,状态才会为finished。悟:Job用来控制生命周期!

 四:coroutineContext的本质

CoroutineContext是一个拥有很多element,这些element可以控制协程行为,有几个默认的coroutineContext,他们有默认值。我有点悟到的一点是,CoroutineContext,协程上下文,本质就是用来控制协程的行为的,比如如何调度,如何控制异常,名字是什么等等。 

子协程会从父协程继承CoroutineContext,规则如下

 我们来看一下上下文的继承规律

val scope = CoroutineScope(Dispatchers.IO+CoroutineName("父协程")+Job())
    scope.launch(CoroutineName("子协程1")) {
        println("key: ${this.coroutineContext[CoroutineDispatcher.Key]}")
        println("Job : ${this.coroutineContext[Job.Key].hashCode()}")
        println("name: ${this.coroutineContext[CoroutineName]}")
        println("----------")
    }.join()
    scope.launch(Dispatchers.Default){
        println("key: ${this.coroutineContext[CoroutineDispatcher.Key]}")
        println("Job : ${this.coroutineContext[Job.Key].hashCode()}")
        println("name: ${this.coroutineContext[CoroutineName]}")
        println("----------")
    }.join()
    scope.launch(CoroutineName("子协程3")){
        println("key: ${this.coroutineContext[CoroutineDispatcher.Key]}")
        println("Job : ${this.coroutineContext[Job.Key].hashCode()}")
        println("name: ${this.coroutineContext[CoroutineName]}")
        println("----------")
    }.join()

结果如下

key: Dispatchers.IO
Job : 1757380160
name: CoroutineName(子协程1)
----------
key: Dispatchers.Default
Job : 444126595
name: CoroutineName(父协程)
----------
key: Dispatchers.IO
Job : 331507349
name: CoroutineName(子协程3)
----------

Process finished with exit code 0
  • 子协程的上下文会覆盖父协程的上下文
  • 子协程会有一个独立的Job对象实例,其实想一下也很清楚,因为Job对象是控制这个协程的生命周期的,自然不能混用
  • 子协程之间互不影响,比如第一个块把name修改,并不会影响第二个块从父协程继承来的name。第二个块对调度器修改并不会影响第三个块继承来的调度器。

 五:协程的取消

悟:cancle a scope!!! cancle all its children.   取消一个子协程,不会影响其他同级的子协程。

这就是协程结构化并发的两个特点:

  • 取消一个协程作用域,将取消该协程作用域下的所有子协程
  • 被取消的子协程,不会影响其它同级的协程

在Android开发中,大部分场景下我们不需要考虑协程的cancel,借助ViewModelScope、LifecycleScope和MainScope这些场景的协程作用域,我们可以很方便的避免内存泄漏,在cancel时结束所有的子协程。

协程的取消是”合作式“的,就像thread被interrupt之后,要在任务逻辑中加一个判断是否被interrupt一样,协程代码块中应该加一个isActive判断或ensureActive();有区别。isActive允许你在知道被取消之后还做点什么,ensureActive直接结束,虽然代码中有throw exception,但并没有抛出异常,我也不知道!!

yield也可以做到ensureActive的效果,但它本意是让步,具体看文档。只不过当这个yield没有去让步去挂起的时候,总是会检查是否被取消,来达到我们取消协程执行的目的。

 delay内部有检查取消的逻辑

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值