You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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") }
   }
}

额外优化建议

  1. 避免使用GlobalScope:GlobalScope属于全局作用域,很难控制生命周期,容易导致内存泄漏。建议使用绑定到组件生命周期的自定义CoroutineScope,比如在Android中用viewModelScope或lifecycleScope。
  2. 配置SharedFlow的replay参数:默认的MutableSharedFlow不会重播历史数据,如果collect调用晚于emit,会错过之前发射的数据。可以在创建时指定replay数量:
    val sharedFlow = MutableSharedFlow<String>(replay = 10) // 重播最近10条数据
    
    这样即使收集操作稍微滞后,也能收到之前发射的内容。

内容的提问来源于stack exchange,提问作者braml1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 13:35:17