协程快速入门

148 阅读3分钟
1. 协程定义:轻量级线程,简单的说就是代码块或者函数调用,一个线程可以包含多个协程
Android 官方已经慢慢集成到自己的框架的 viewmodel中
Rtrofit2.6.0 以上已经支持协程,可能后续会变成主流的操作
2. 协程、线程、进程比较
区别 协程 线程 进程
定义 轻量线程 运算调度最小单位 一段程序的执行过程
占用资源 单线程,子程序切换,程序自身可控 多线程消耗资源大,线程执行不可控
数据共享 单线程,不需要要加锁效率高 需要加锁,效率低下
可读性 同步代码相似,可读性高 线程间切换需要嵌套,可读性低
Thread代码比较 GlobalScope.launch { …… } thread { …… }
Thread.sleep代码比较 delay(……) Thread.sleep(……)
3、开始使用
Android中使用协程 kotlin版本必须大于1.3.+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2'
4、名词解释
作用域: 执行代码的线程
上下文: 是一组各种元素的集合。 主要元素是协程的Job及其调度器
挂起:   暂时不执行
调度器: 可以切换线程
协程体: 执行代码的地方
5、生命周期
isActive:是否活动
isCompleted:是否完成
isCancelled:是否取消
6、协程使用方法
名称 作用
runBlocking 创建一个会阻塞当前线程的Coroutine
launch 创建一个不会阻塞当前线程、没有返回结果的 Coroutine,但会返回一个 Job 对象,可以用于控制这个 Coroutine 的执行和取消
async 创建一个不会阻塞当前线程、有返回结果的 Coroutine,但会返回一个 Deferred 对象,可以用于控制这个 Coroutine 的执行和取消,Deferred.await()可以获取结果
flow 创建异步流,可以执行多个事件
7、参数解析
CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
)
context: CoroutineContext: 即上下文,是一组各种元素的集合。 主要元素是协程的Job及其调度器
启动模式 CoroutineStart
模式 功能
DEFAULT 立即执行协程体
ATOMIC 立即执行协程体,但在开始运行之前无法取消
UNDISPATCHED 立即在当前线程执行协程体,直到第一个 suspend 调用
LAZY 需要时候调用start运行
协程体 block: suspend CoroutineScope.() 即我们执行代码地方
8、协程启动
fun main() = runBlocking{
    
}

fun main() = launch{
    
}

fun main() = async{
    
}

suspend 修饰的方法可以在协程中执行,即挂起函数
9、协程取消
1. 取消协程执行
val job = launch{
    
}

job.cancel()

2、取消计算代码
val job = launch{
    while(isActive){
        
    }
}
job.cancelAndJoin()

3、超时
withTimeout() {
//抛出TimeoutCancellationException代表取消协程
}

withTimeoutOrNull(){
//返回null 代表取消协程
}
10、协程上下文与调度器
模式 功能
Dispatchers.Default 运行父协程的上下文
Dispatchers.Unconfined 事件线程池, 即有执行顺序的
Dispatchers.IO 使用IO线程池
newSingleThreadContext 创建新线程
launch(Dispatchers.IO) {//运行在IO线程
    withContext(Dispatchers.Main){
    //回到Main线程,可以进行修改UI
    }
}
11、异步流
异步流的主要功能就是执行一串事件,例如for循环,while循环
流的构建两种方式
1、flow { // 流构建器
    for (i in 1..3) {
        delay(100) // 假装我们在这里做了一些有用的事情
        emit(i) // 发送下一个值
    }.collect { value -> println(value) //获取emit发送的参数 } 
}

2、(1..3).asFlow().collect { value -> println(value) }
流的操作符(操作符比较多,就挑选几个日常常用的,使用方式与list的差不多,可以查看kotlin官方)

filter:过滤操作符
transform:转换操作符
take:限长操作符
12、通道
val channel = Channel<Int>()
launch {
    // 这里可能是消耗大量 CPU 运算的异步逻辑,我们将仅仅做 5 次整数的平方并发送
    for (x in 1..5) channel.send(x * x)
}
// 这里我们打印了 5 次被接收的整数:
repeat(5) { println(channel.receive()) }