Kotlin中SharedFlow无法收集数据问题求助
问题描述
我有一个发射Flow的类,另一个类的函数负责收集该Flow:
可正常运行的代码
class DebugMessage { val sharedFlow = MutableSharedFlow<String>() fun makeFlow() { GlobalScope.launch(Dispatchers.Default) { for (i in 0 until 10) { sharedFlow.emit(Random.nextInt(1,100).toString()) delay(200) } } } fun getFlow(): Flow<String> { makeFlow() return sharedFlow } }
收集代码:
private fun collectDebugMsg() { GlobalScope.launch(Dispatchers.Default) { val getFlow = DebugMessage().getFlow() getFlow.collect { Timber.d("VALUE IS $it") } } }
这段代码可以正常运行,但实用性不足。我想拆分makeFlow和getFlow函数,改为从外部先调用makeFlow再调用getFlow,但修改后无法收集到任何数据:
无法运行的代码
class DebugMessage { val sharedFlow = MutableSharedFlow<String>() fun makeFlow() { GlobalScope.launch(Dispatchers.Default) { for (i in 0 until 10) { sharedFlow.emit(Random.nextInt(1,100).toString()) delay(200) } } } fun getFlow(): Flow<String> { // 不再内部调用makeFlow,改为外部调用 return sharedFlow } }
收集代码:
private fun collectDebugMsg() { GlobalScope.launch(Dispatchers.Default) { DebugMessage().makeFlow() // 外部调用makeFlow val getFlow = DebugMessage().getFlow() getFlow.collect { Timber.d("VALUE IS $it") } } }
请问这是什么原因?
问题原因与解决方案
核心原因
你犯了一个典型的实例复用错误:每次调用DebugMessage()都会创建一个全新的DebugMessage对象。
- 第一个
DebugMessage()实例调用makeFlow()后,它内部的sharedFlow开始发射数据; - 但你调用
DebugMessage().getFlow()时,又创建了第二个完全独立的DebugMessage实例,它的sharedFlow根本没有被触发发射数据,自然收集不到任何内容。
修复方案
只创建一个DebugMessage实例,复用它完成makeFlow()调用和Flow收集:
private fun collectDebugMsg() { GlobalScope.launch(Dispatchers.Default) { val debugMsg = DebugMessage() // 只创建一次实例 debugMsg.makeFlow() val getFlow = debugMsg.getFlow() getFlow.collect { Timber.d("VALUE IS $it") } } }
额外优化建议
- 避免使用
GlobalScope:GlobalScope属于全局作用域,很难控制生命周期,容易导致内存泄漏。建议使用绑定到组件生命周期的自定义CoroutineScope,比如在Android中用viewModelScope或lifecycleScope。 - 配置
SharedFlow的replay参数:默认的MutableSharedFlow不会重播历史数据,如果collect调用晚于emit,会错过之前发射的数据。可以在创建时指定replay数量:
这样即使收集操作稍微滞后,也能收到之前发射的内容。val sharedFlow = MutableSharedFlow<String>(replay = 10) // 重播最近10条数据
内容的提问来源于stack exchange,提问作者braml1
相关产品推荐
相关产品推荐

