Please enable JavaScript.
Coggle requires JavaScript to display documents.
kotlin协程 (Flow流 (一些操作 (处理流 (collectLatest() collect每次获取最新值,如果collect比生产慢,当…
kotlin协程
Flow流
特点
流可以延迟生产多个值并返回,而sequence不行
构建器
flow { ... }
flowOf
.asFlow()
操作符(可以执行suspend函数)
map
filter
转换操作符 transform ,可以发送这个值,并对这个值做特殊处理
限长操作符 take 只取前几个值
末端操作符 reduce,toList,collect等
流是连续的
每次单独收集都是按顺序执行的,除非进行特殊操作的操作符使用多个流。该收集过程直接在协程中运行,该协程调用末端操作符。
上下文环境
流的收集总是在调用协程的上下文中发生
改变构建器所在的上下文环境:.flowOn(Dispatchers.Default)
一些操作
处理流
collectLatest() collect每次获取最新值,如果collect比生产慢,当新值产生时会取消掉之前没完成的collect,然后处理新的值
conflate 只会使用当前collect请求时产生的值,其他值会被丢弃
buffer()可以将上游的代码在单独的协程上下文中进行
联合
zip
combine
展平流
flatMapConcat
flatMapMerge
flatMapLatest
流异常
try/catch block
透明捕获 catch
流完成
try/finally
onCompletion()
收集
launchIn
collect
通道Channel
通道提供了一种在流中传递值的方法
操作方法
Channel.send
ReceiveChannel.consumeEach()
Channel.close
ReceiveChannel.cancel()
Channel.receive
CoroutineScope.produce
管道
一个协程生产无穷多个元素;另一个或多个协程消耗这些流
操作
扇入
多个协程可以发送到同一个通道。
扇出
多个协程也许会接收相同的管道,在它们之间进行分布式工作。
分类
带缓冲的
val channel = Channel<Int>(4) // 启动带缓冲的通道
可以预先生产多个待消耗,在缓冲区满了后阻塞
不带缓冲的
只有消费前才会生产
特点
发送和接收操作是 公平的 并且尊重调用它们的多个协程。它们遵守先进先出原则
计时器通道
每隔一段时间都会产生一个Unit,其余时间返回null,具体间隔受TrickerModel控制
取消与超时
cancel
cancelAndJoin
withContext(NonCancellable) {//此处的协程不可取消}
withTimeout(1300L) {//超时抛出异常}
withTimeoutOrNull(1300L){超时返回null}
异常
传播
自动传播异常(打印) launch actor
抛出异常让用户处理 async produce
CoroutineExceptionHandler
仅在预计不会由用户处理的异常上调用,将通用的 catch 代码块用于在协程中自定义日志记录或异常处理。
特点:需要放在 GlobalScope 启动的协程,放在其他子协程中没有意义。异常发生时子协程和同级的子协程都会被取消,然后将异常传递给父协程
取消与异常
CancellationException
用来取消协程,会被异常处理器忽略
监督(取消是单向的)
监督作业
SupervisorJob 取消只会向下传播
监督作用域
supervisorScope 只会单向的传播并且当子作业自身执行失败的时候将它们全部取消。它也会在所有的子作业执行结束前等待
监督协程中的异常
子协程作业失败,不会取消父协程
select
onReceive 同时从生产者接收数据,通道关闭的时候会报错
onReceiveOrNull 可以在关闭通道时执行特定操作
onSend 发送消息
onAwait 查询延迟值
在延迟值通道上切换
调度器
Dispatchers.Unconfined 不受限 即上一段语句在什么线程,他就在什么线程
Dispatchers.Default 共享后台线程池中的某个线程
newSingleThreadContext("MyOwnThread") 新建一个线程
不指定 从启动了它的 CoroutineScope 中承袭了上下文(以及调度器)
共享的可变状态与并发
使用线程安全的数据结构
以细粒度将对共享状态的操作控制在一个线程
只将所有 UI 状态都局限于单个事件分发线程或应用主线程中
以粗粒度将对共享状态的操作控制在一个线程
在单线程上下文中运行每个协程
Actors
一个 actor 是由协程、 被限制并封装到该协程中的状态以及一个与其它协程通信的 通道 组合而成的一个实体。
运行方式
GlobalScope
runBlocking
coroutineScope
子协程与父协程
父协程总是等待所有的子协程执行结束
父协程被取消的时候,所有它的子协程也会被递归的取消。
当使用 GlobalScope 来启动一个协程时,则新协程的作业没有父作业。 因此它与这个启动的作用域无关且独立运作
协程局部变量
使用ThreadLocal、asContextElement()实现,与协程所在线程无关
详见:
https://github.com/jixiaoyong
直接改变ThreadLocal的值,会在切换协程后失效,即使在切换回该协程,也只能读取到上一个通过asContextElement()更新的值
原理:启动和恢复时保存ThreadLocal在当前线程的值,并修改为 value,挂起和结束时修改当前线程ThreadLocal的值为之前保存的值。
协程构建器
launch
launch 返回一个 Job 并且不附带任何结果值
async
async 返回一个 Deferred —— 一个轻量级的非阻塞 future,可以使用 .await()获取返回值
async(start = CoroutineStart.LAZY) { //start()或await()时才会执行 }