一文吃透Kotlin中冷流(Clod Flow)和热流(Hot Flow)

353 阅读2分钟

一、冷流(Cold Flow)

特点:

  • 按需触发:只有调用 collect() 时,才开始生产数据。
  • 独立副本:每个新的订阅者都会触发完整的数据流从头开始。
  • 典型代表flow { ... }asFlow()

冷流示例代码:

//每次collect都会重新发射数据 
val coldFlow = flow { 
    println("开始生产数据") //每次collect都会执行 
    emit(1) 
    emit(2) 
} 

// 第一个订阅者 
coldFlow.collect { println("订阅者1: $it") } // 输出:1,2 
// 第二个订阅者 
coldFlow.collect { println("订阅者2: $it") } // 再次输出:1,2

适用场景:

  • 如网络请求、数据库查询,即需要独立数据源场景。
  • 每个订阅者需要从头消费完整的数据。

总结:

冷流像【点播电影】,你点播才开始播放,不同观众各自从头开始看。

二、热流(Hot Flow)

特点:

  • 主动发射:不管有没有订阅者,数据都会产生。
  • 共享数据源:多个订阅者共享同一份数据流,但只能收到订阅后的数据。
  • 典型代表SharedFlowStateFlow

热流示例代码:

// 创建热流(SharedFlow) 
val hotFlow = MutableSharedFlow<Int>()

// 启动协程持续发射数据(即使没有订阅者)
CoroutineScope(Dispatchers.Default).launch { 
    repeat(3) { 
        delay(1000) 
         // 发射 0 1 2
        hotFlow.emit(it)
    } 
}

// 第一个订阅者(延迟1秒订阅) 
CoroutineScope(Dispatchers.Main).launch {
    delay(1000) 
    hotFlow.collect { println("订阅者1: $it") } // 只能收到 1,2
} 

// 第二个订阅者(延迟5秒订阅) 
CoroutineScope(Dispatchers.Main).launch { 
    delay(5000) 
    hotFlow.collect { println("订阅者2: $it") } // 收不到任何数据(发射已结束) 
}

适用场景:

  • 需要共享实时数据的场景(如IM消息、用户定位更新)。
  • 多个订阅者需要获取同一份动态数据(如全局状态管理)。

总结:

热流像【直播】,不管你看不看,节目都在进行,中途进入的只能从当前内容开始看。

三、 冷流(Cold Flow) vs 热流(Hot Flow)

冷流(Cold Flow)热流(Hot Flow)
数据发射时机按需触发(有订阅才发射)主动发射(不管有没有订阅)
数据独立性每个订阅者获取独立副本所有订阅者共享同一数据源
数据历史新订阅者从头获取完整数据新订阅者只能获取订阅后的数据
典型用例单次网络请求、文件读取实时状态更新、事件总线
资源消耗每次订阅都重新执行逻辑(重复耗时)单次数据源共享(节约资源)

开发中如何选择使用冷/热流?

冷流(私人订制)

  • 每个订阅者需要独立完整的数据(如每次打开页面都重新请求最新数据)。
  • 数据生产逻辑需要按需触发(如按钮点击才加载数据)。

热流(直播)

  • 需要多个订阅者共享实时数据(如全局登录状态)。
  • 数据生产是持续且独立的(如实时定位数据、传感器数据、WebSocket消息)。

更多分享

  1. # 一文带你吃透Kotlin协程的launch()和async()的区别
  2. Kotlin日常高效编程技巧和作用域函数的使用。