协程解析:
- 轻量级线程。在一个线程中可以启动多个协程。
- 在协程中使用同步方式写出异步代码(协程挂起时不会阻塞线程)。
GlobalScope.launch(Dispatchers.Main) {//开始协程:主线程
val result = userApi.getUserSuspend("suming")//网络请求(IO 线程)
tv_name.text = result?.name //更新 UI(主线程)
}
协程关于线程切换的四种调度器:
- Dispatchers.Default:默认调度器。它使用JVM的共享线程池,该调度器的最大并发度是CPU的核心数,默认为2。
- Dispatchers.Unconfined:非受限调度器。该调度器不会限制代码在指定的线程上执行。即挂起函数后面的代码不会主动恢复到挂起之前的线程去执行,而是在执行挂起函数的线程上执行。
- Dispatchers.IO:IO调度器。它将阻塞的IO任务分流到一个共享的线程池中。该调度器和Dispatchers.Default共享线程。
- Dispatchers.Main:主线程调度器。一般用于操作与更新UI。
(Dispatchers.Default调度器和Dispatchers.IO 调度器分配的线程为守护线程。)
协程共有以下四种启动模式:
- CoroutineStart.DEFAULT:立即执行协程,可以随时取消。
- CoroutineStart.LAZY:创建一个协程,但不执行,在用户需要时手动触发执行。
- CoroutineStart.ATOMIC:立即执行协程,但在协程执行前无法取消。目前处于试验阶段。
- CoroutineStart.UNDISPATCHED:立即在当前线程执行协程,直到遇到第一个挂起。目前处于试验阶段。
还有一个问题就是关于协程的上下文,它们均继承自CoroutineContext::
- Job:协程的句柄,对协程的控制和管理生命周期。
- CoroutineName:协程的名称,可用于调试。
- CoroutineDispatcher:调度器,确定协程在指定的线程来执行。
- CoroutineExceptionHandler:协程异常处理器,处理未捕获的异常。
经常和协程搭配使用的还有一个kotlin操作符flow,记一下其使用方式:
(1)flow{ … }内部可以调用suspend 函数;
(2)使用 emit() 方法来发射数据;
(3)使用 collect() 方法来收集结果。
例如:上流
fun simpleFlow() = flow {
for (i in 1..3) {
delay(100)
emit(i)
}
}
fun main() {
runBlocking {
//下流处理数据
simpleFlow().collect { value ->
println(value)
}
println("finished")
}
}
结果:
1
2
3
finished
2、Flow是冷流,所以collect是挂起函数,不是子协程,并且只有执行collect函数时,上流的代码才会被执行,所以在一个协程中多次调用collect,它们会按顺序执行。
fun simpleFlow() = flow {
for (i in 1..3) {
delay(100)
emit(i)
}
}
fun main() {
runBlocking {
simpleFlow().collect { value ->
println(value)
}
println("collect1 finished")
simpleFlow().collect { value ->
println(value)
}
println("collect2 finished")
}
}
结果:
1
2
3
collect1 finished
1
2
3
collect2 finished
创建一个简单地flow
flow {
(5 .. 10).forEach {
emit(it)
}
}.collect{
println(it)
}