先把构造函数放这里方便查看
public fun <T> MutableSharedFlow(
replay: Int = 0,//
extraBufferCapacity: Int = 0,
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): MutableSharedFlow<T> {}
场景1:在没有配置buffer的情况下(extraBufferCapacity为0),且是慢接收者,那么发送的消息会丢吗?
先说答案:消息不会丢,消息会被封装成Emitter放入buffer中,你没看错,即使extraBufferCapacity是0,也会创建buffer;
关键是看消息发送emit函数
注释1:如果发送成功,接收者没有挂起或者buffer有空间(配置extraBufferCapacity大于0的情况下)或者可以抛弃消息,则直接返回true;
注释2:基于我们的场景,那么tryEmit会返回false(因为被挂起了),而emitSuspend最后会走到enqueueLocked,把消息封装成Emitter放入buffer集合中;
override suspend fun emit(value: T) {
if (tryEmit(value)) return // 1
emitSuspend(value)//2
}
注释1:因为一开始buffer为null,所有走创建长度为2的分支; 注释2: 如果buffer不会null,且容量不够就会扩容,否则直接保存;
private fun enqueueLocked(item: Any?) {
val curSize = totalSize
val buffer = when (val curBuffer = buffer) {
null -> growBuffer(null, 0, 2)//1
else -> if (curSize >= curBuffer.size) growBuffer(curBuffer, curSize,curBuffer.size * 2) else curBuffer//2
}
buffer.setBufferAt(head + curSize, item)
}
细心的同学可能会发现,即使extraBufferCapacity为0,也有创建buffer集合;
场景2:Activity、Fragment 销毁,那么接收者协程是否也会同步取消;
先说答案:接收者协程会被同步取消,所以不用考虑内存泄露的问题;
关键看collect的代码
注释1:尝试获取value;
注释2:如果获取到了,则跳出内存循环,触发注释3进行回调,否则再次进入循环;
大家可能注意到了,在触发collector.emit之前,会collectorJob?.ensureActive()来判断协程状态;以lifecycleScope注册collect为例,当Activity onDestory执行时,lifecycleScope内部所有协程都cancel,使得isActive判断会返回false; 还有一个关键点,collect是挂起函数,当Activity onDestory执行时collect也是会被cancel的,也就是while循环就结束了。
override suspend fun collect(collector: FlowCollector<T>) {
val slot = allocateSlot()
try {
......
while (true) {
var newValue: Any?
while (true) {
newValue = tryTakeValue(slot) // 1
if (newValue !== NO_VALUE) break// 2
awaitValue(slot)
}
collectorJob?.ensureActive()
collector.emit(newValue as T)//3
}
} finally {
freeSlot(slot)
}
}
判断协程是否存活,否则抛出异常,这个异常是会被内部消化掉,所以不用担心应用崩溃;
public fun Job.ensureActive(): Unit {
if (!isActive) throw getCancellationException()
}