MutableSharedFlow
创建方法
public fun <T> MutableSharedFlow(
replay: Int = 0,
extraBufferCapacity: Int = 0,
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): MutableSharedFlow<T> {
require(replay >= 0) {
"replay cannot be negative, but was $replay" }
require(extraBufferCapacity >= 0) {
"extraBufferCapacity cannot be negative, but was $extraBufferCapacity" }
require(replay > 0 || extraBufferCapacity > 0 || onBufferOverflow == BufferOverflow.SUSPEND) {
"replay or extraBufferCapacity must be positive with non-default onBufferOverflow strategy $onBufferOverflow"
}
val bufferCapacity0 = replay + extraBufferCapacity
val bufferCapacity = if (bufferCapacity0 < 0) Int.MAX_VALUE else bufferCapacity0
return SharedFlowImpl(replay, bufferCapacity, onBufferOverflow)
}
SharedFlowImpl
构造函数
replay
: 重放数目,重放 bufferEndIndex
前 replay
个元素, bufferEndIndex-1
为最快的 collector
bufferCapacity
: 缓存区总大小,用于决定最快的收集器和最慢收集器相差的最大差距,由 replay
和 extraBufferCapacity
相加而得
onBufferOverFlow
: 缓存溢出策略,可设置三种
DROP_OLDEST
: 丢弃最老的
DROP_LASTEST
: 丢弃最新的
SUSEPND
: 挂起 => 这个策略在溢出的时候不可 tryEmit
SharedFlowImpl
存储的状态和关键索引
buffer
: 存放最近弹出 bufferSize
个元素和 queueSize
个排队发射器
queueSize
: 排队发射器的数量
bufferSize
: 最近弹出的元素,容量由 bufferCapacity
决定
minCollectorIndex
: 活跃收集器的最小索引,没有活跃的收集器的时候等于 replayIndex
,当源码中没有收集器的时候值为 bufferEndIndex
, 不过有收集器的时候都会矫正
replayIndex
: 新收集器获取的索引 => 因为需要回放最近 replay
个元素
SharedFlowImpl
计算状态
head(buffer的头索引)
: minOf(minCollectorIndex, replayIndex)
replaySize(当前存在的回放数量)
: (head + bufferSize - replayIndex).toInt()
totalSize(buffer的总大小)
: bufferSize + queueSize
bufferEndIndex(缓存弹出过的数据最后的索引)
: head + bufferSize
queueEndIndex(buffer最后的索引)
: head + bufferSize + queueSize
SharedFlowImpl#buffer
官方定义结构图
SharedFlowImpl
发射流程
SharedFlowImpl#emit(value:T)
: 发射
override suspend fun emit(value: T) {
if (tryEmit(value)) return
emitSuspend(value)
}
SharedFlowImpl#tryEmit(value:T)
: true代表发射成功,false代表发射失败
override fun tryEmit(value: T): Boolean {
var resumes: Array<Continuation<Unit>?> = EMPTY_RESUMES
val emitted = synchronized(this) {
if (tryEmitLocked(value)) {
resumes = findSlotsToResumeLocked(resumes)
true
} else {
false
}
}
for (cont in resumes) cont?.resume(Unit)
return emitted
}
SharedFlowImpl#emitSuspend(value:T)
: 发射挂起
private suspend fun emitSuspend(value: T) = suspendCancellableCoroutine<Unit> sc@{
cont ->
var resumes: Array<Continuation<Unit>?> = EMPTY_RESUMES
val emitter = synchronized(this) lock@{
if (tryEmitLocked(value)) {
cont.resume(Unit)
resumes = findSlotsToResumeLocked(resumes)
return@lock null
}