1 什么是协程 轻量级线程,kotlin在1.3版本后,提供了协程coroutine库,一种简化异步任务处理的方案。
2 为什么用协程
2.1 简化代码,增加可读性
使用协程可以用简洁直观可读性高的写法,实现多重依赖关系的异步任务的书写。
若不使用协程,一般的异步方式?
- 通过Callback回调的方式
- 利用AsyncTask
- 通过链式调用
java8提供的CompletableFuture
使用RXJava这种链式实现多重依赖的异步任务,可以解决回调嵌套问题,相比于callback回调可读性好。 - 新启线程
.......
- 协程依赖于线程的使用,挂起协程不会阻塞线程,后续执行和复用,轻量级
- 在协程默认的线程池中,处理逻辑更偏向在当前线程的任务队列中添加任务,而不是开启新的工作线程
- 在多cpu情况下,会开启不超过cpu数的线程数并可以从其他线程的任务队列中抢夺任务,最大程度地复用已有的工作线程。
协程是一套管理和运行异步任务的框架,所以需要有运行的环境,也叫协程的作用域,在这个作用域里,才可以使用协程来执行异步任务。
(1) 全局环境
GlobalScope.launch {}
GlobalScope代表协程的全局作用域,在该作用域启动的协程为顶层协程,没有父任务,且该scope没有Job对象,所以无法对整个scope执行cancel()操作,
所以如果没有手动取消每个任务,会造成这些任务一直运行,可能会导致内存泄露等问题。
(2) 局部环境
CoroutineScope(Dispatchers.Main).launch {}
通常会通过创建CoroutineScope,来实现一个协程作用域,并且可以指定派发器,可以取消该scope下所有正在进行的任务。
3.2 协程派发器
kotlin提供的一些默认的Dispatcher:
名称 | 说明 |
---|---|
Dispatchers.IO | 工作线程池,依赖于Dispatchers.Default,支持最大并行任务数 |
Dispatchers.Main | 主线程,这个在不同平台定义不一样,所以需要引入相关的依赖,比如Android平台,需要使用包含MainLooper的handler来向主线程派发 |
Dispatchers.Default | Dispatchers.Default |
Dispatchers.Unconfined | 无指定派发线程,会根据运行时的上线文环境决定 |
3.3 启动协程任务
(1) 对于一个scope对象,常用launch和async创建协程。
CoroutineScope(Dispatchers.IO).launch { }
CoroutineScope(Dispatchers.IO).async { }
而两者的最大不同是,async会创建一个Deferred的协程,可以用来等待该协程执行完毕再进行后续操作。
(2) 内部协程
|
在一个协程内部,也可以创建子协程。
(3)改变协程任务执行环境
如IO线程执行异步请求,数据回来后在主线程进行展示。
|
协程可以顺序完成异步任务,那么在等待上一个协程任务完成时,当前的协程需要被挂起(不阻塞线程)
|
withContext()方法,除了可以指定启动协程任务外,还可以挂起当前协程,即外部的launch的协程,直到withContext启动的协程任务完成后,才会重新恢复外部的launch协程,执行下面的async语句。
使用suspend关键字
|
4协程实现原理 4.1 基本原理
三剑客:协程作用域,dispatcher,coroutine
简化结构关系:
文章图片
详细关系图:
文章图片
文章图片
基本流程:在作用域启动协程,调度器调度,若协程挂起,则调度其他协程或者执行其他主协程代码
【kotlin协程原理】
推荐阅读
- 快速上手 Kotlin 开发系列之函数与函数嵌套
- 加深学习|android属性动画(Kotlin)
- android|一个简单的Android圆形ProgressBar
- Kotlin专题「十一」(可见性修饰符(private、protected、internal、public))
- Kotlin专题「十」(接口与函数接口(Functional (SAM) interfaces))
- Kotlin专题「十三」(数据类(Data Classes))
- Kotlin专题「十四」(密封类(Sealed Classes))
- Kotlin专题「十二」(扩展Extensions(扩展函数与属性))
- Android开发者快速上手Kotlin(三) 之 高阶函数和SAM转换
- kotlin数字与java数字的不同