Flow的分类

9 阅读6分钟

一、Flow 核心分类(基于 Kotlin 协程 1.7.3+ 最新规范)

Kotlin Flow 是基于协程的冷流响应式框架,核心按数据流特性分为 4 大类,各类别设计目标、生命周期、使用场景差异显著:

分类核心特性冷热属性关键特征典型使用场景
普通 Flow(冷流)被动触发:每次收集(collect)才执行上游发射逻辑,无收集则无计算冷流1. 无初始值;2. 多收集者各自独立执行;3. 取消收集则停止发射单次数据请求(如网络接口、数据库查询)
StateFlow热流:始终持有最新值,新收集者立即获取当前值,仅发射更新后的值热流1. 必须有初始值;2. 仅发射与当前值不同的新值;3. 生命周期与持有者绑定UI 状态管理(如按钮是否可用、列表数据)
SharedFlow热流:可缓存历史值,支持多收集者共享数据,可配置重放策略热流1. 可选初始值;2. 支持重放历史值、限流;3. 多订阅者共享同一份数据事件通知(如弹窗、Toast、导航指令)
Channel Flow基于 Channel 的 Flow:支持背压策略,适配生产者 - 消费者模型冷 / 热流1. 可选缓冲策略;2. 支持多生产者 / 多消费者;3. 取消后立即停止高频数据生产(如传感器、实时日志)

二、各类 Flow 详细解析(定义 + 区别 + 使用示例)

前置依赖(必加)

// 协程核心
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
// Compose 适配(如需在 Compose 中使用)
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.7.0"

1. 普通 Flow(冷流)

核心定义

最基础的 Flow,通过 flow { ... } 构建,无收集则不执行发射逻辑,每个收集者都会触发上游重新执行(比如网络请求会重复调用)。

关键区别

  • 冷流:“懒加载” 特性,收集者是 “触发开关”;
  • 无初始值,无缓存,取消收集后上游立即停止;
  • 多收集者相互独立(A 收集和 B 收集会各自执行一次发射逻辑)。

完整使用示例

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

// 1. 构建普通 Flow(模拟网络请求/数据库查询)
fun fetchUserData(): Flow<String> = flow {
    println("开始执行发射逻辑(仅当有收集者时执行)")
    // 模拟耗时操作
    delay(1000)
    emit("用户数据1") // 发射数据
    delay(500)
    emit("用户数据2")
}

// 2. 使用普通 Flow
fun main() = runBlocking {
    val userFlow = fetchUserData()

    // 收集者1:触发第一次发射
    launch {
        userFlow.collect { data ->
            println("收集者1接收:$data")
        }
    }

    // 延迟2秒,确保收集者1执行完毕
    delay(2000)

    // 收集者2:触发第二次发射(上游逻辑重新执行)
    launch {
        userFlow.collect { data ->
            println("收集者2接收:$data")
        }
    }
}

// 输出结果:
// 开始执行发射逻辑(仅当有收集者时执行)
// 收集者1接收:用户数据1
// 收集者1接收:用户数据2
// 开始执行发射逻辑(仅当有收集者时执行)
// 收集者2接收:用户数据1
// 收集者2接收:用户数据2

典型场景

  • 单次异步请求(如 Retrofit 接口封装为 Flow);
  • 一次性数据计算(如解析本地文件)。

2. StateFlow(热流)

核心定义

StateFlow 是 SharedFlow 的特化版,始终持有最新值,适合存储 “状态”(如 UI 显示的文本、开关状态)。

关键区别

  • 热流:无论是否有收集者,只要更新值就会存储(但仅当有收集者时发射);
  • 必须有初始值,仅发射与当前值不同的新值(避免重复更新);
  • 多收集者共享同一份最新值(新收集者立即获取当前值)。

完整使用示例

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

// 1. 构建 StateFlow(UI 状态管理示例)
class UiStateManager {
    // 私有可变 StateFlow(仅内部可更新)
    private val _uiState = MutableStateFlow<String>("初始状态")
    // 公开不可变 StateFlow(外部仅可收集)
    val uiState: StateFlow<String> = _uiState.asStateFlow()

    // 更新状态
    fun updateState(newState: String) {
        _uiState.value = newState // StateFlow 用 value 更新值
    }
}

// 2. 使用 StateFlow
fun main() = runBlocking {
    val stateManager = UiStateManager()

    // 收集者1:立即接收初始值,后续接收更新值
    launch {
        stateManager.uiState.collect { state ->
            println("收集者1接收状态:$state")
        }
    }

    // 延迟500ms,更新状态
    delay(500)
    stateManager.updateState("加载中")

    // 延迟500ms,添加收集者2(立即接收最新值“加载中”)
    delay(500)
    launch {
        stateManager.uiState.collect { state ->
            println("收集者2接收状态:$state")
        }
    }

    // 延迟500ms,更新重复值(不会发射,因为与当前值相同)
    delay(500)
    stateManager.updateState("加载中")

    // 延迟500ms,更新新值
    delay(500)
    stateManager.updateState("加载完成")
}

// 输出结果:
// 收集者1接收状态:初始状态
// 收集者1接收状态:加载中
// 收集者2接收状态:加载中
// 收集者1接收状态:加载完成
// 收集者2接收状态:加载完成

Compose 中使用(最新 API)

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsStateWithLifecycle
import androidx.compose.material3.Text

@Composable
fun StateFlowComposeDemo(manager: UiStateManager) {
    // 自动感知生命周期,后台暂停收集
    val uiState by manager.uiState.collectAsStateWithLifecycle()
    Text(text = "当前状态:$uiState")
}

典型场景

  • Compose/Android 页面状态管理(如标题文本、列表数据、按钮是否禁用);
  • ViewModel 中存储 UI 相关的可变状态。

3. SharedFlow(热流)

核心定义

通用型热流,支持缓存历史值、配置重放策略、限流,适合传递 “事件”(如弹窗通知、导航指令)。

关键区别

  • 热流:无初始值(可选),可配置重放历史值数量;
  • 支持多收集者共享数据,可设置 “额外缓冲区” 和 “限流策略”;
  • 不过滤重复值(与 StateFlow 核心区别)。

核心参数说明

// MutableSharedFlow 构建参数
MutableSharedFlow<T>(
replay = 0, // 重放历史值数量(新收集者接收的历史值数)
extraBufferCapacity = 0, // 额外缓冲区大小(超出则触发限流策略)
onBufferOverflow = BufferOverflow.SUSPEND // 限流策略:SUSPEND(挂起)/DROP_OLDEST/DROP_LATEST
)

完整使用示例

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

// 1. 构建 SharedFlow(事件通知示例)
class EventManager {
    // 配置:重放1条历史事件,额外缓冲区2,超出则丢弃最旧事件
    private val _eventFlow = MutableSharedFlow<String>(
        replay = 1,
        extraBufferCapacity = 2,
        onBufferOverflow = BufferOverflow.DROP_OLDEST
    )
    val eventFlow: SharedFlow<String> = _eventFlow.asSharedFlow()

    // 发送事件
    suspend fun sendEvent(event: String) {
        _eventFlow.emit(event) // SharedFlow 用 emit 发射(挂起函数)
    }
}

// 2. 使用 SharedFlow
fun main() = runBlocking {
    val eventManager = EventManager()

    // 先发送2个事件(此时无收集者,replay=1 会缓存最后1个)
    eventManager.sendEvent("事件1")
    eventManager.sendEvent("事件2")

    // 收集者1:立即接收重放的1个历史事件(事件2)
    launch {
        eventManager.eventFlow.collect { event ->
            println("收集者1接收事件:$event")
        }
    }

    delay(500)
    // 发送3个事件(超出缓冲区:replay=1 + extraBufferCapacity=2 = 3,第4个会触发限流)
    repeat(4) {
        eventManager.sendEvent("新事件$it")
        delay(100)
    }

    // 收集者2:接收重放的1个历史事件(最后1个新事件)
    delay(500)
    launch {
        eventManager.eventFlow.collect { event ->
            println("收集者2接收事件:$event")
        }
    }
}

// 输出结果:
// 收集者1接收事件:事件2
// 收集者1接收事件:新事件0
// 收集者1接收事件:新事件1
// 收集者1接收事件:新事件2
// 收集者1接收事件:新事件3
// 收集者2接收事件:新事件3

Compose 中使用

@Composable
fun SharedFlowComposeDemo(manager: EventManager) {
    // 收集事件(推荐在 LaunchedEffect 中收集,避免重组重复收集)
    LaunchedEffect(Unit) {
        manager.eventFlow.collect { event ->
            // 处理事件(如弹Toast、导航)
            println("处理事件:$event")
        }
    }
}

典型场景

  • 跨页面 / 组件的事件通知(如弹窗、Toast、错误提示);
  • 导航指令(如从 ViewModel 通知页面跳转到详情页);
  • 实时消息推送(如聊天消息、系统通知)。

4. Channel Flow(通道流)

核心定义

基于 Channel 实现的 Flow,适配生产者 - 消费者模型,支持自定义背压策略,可作为 “冷流” 或 “热流” 使用。

关键区别

  • 支持多生产者、多消费者;
  • 可配置缓冲策略(与 SharedFlow 类似,但更底层);
  • 取消收集后立即停止发射,适合高频数据生产。

完整使用示例


import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

// 1. 构建 Channel Flow(模拟传感器数据采集)
fun sensorDataFlow(): Flow<Int> = channelFlow {
    // 生产者1:模拟传感器1数据
    launch {
        repeat(3) {
            send(it * 10) // 发送数据到通道
            delay(200)
        }
    }

    // 生产者2:模拟传感器2数据
    launch {
        repeat(3) {
            send(it * 100)
            delay(300)
        }
    }

    // 延迟1秒后关闭通道
    delay(1000)
    close()
}

// 2. 使用 Channel Flow
fun main() = runBlocking {
    sensorDataFlow().collect { data ->
        println("接收传感器数据:$data")
    }
}

// 输出结果(顺序由延迟决定):
// 接收传感器数据:0
// 接收传感器数据:0
// 接收传感器数据:10
// 接收传感器数据:100
// 接收传感器数据:20
// 接收传感器数据:200

典型场景

  • 高频数据生产(如传感器数据、实时日志、串口数据);
  • 多生产者向同一消费者发送数据;
  • 需要精细控制背压策略的场景。

三、各类 Flow 核心区别总结表

特性普通 FlowStateFlowSharedFlowChannel Flow
冷热属性冷流热流热流冷 / 热流
初始值必须有可选
重复值过滤过滤(仅发射不同值)不过滤不过滤
多收集者各自独立执行共享最新值共享历史 / 新值共享通道数据
缓存 / 重放仅最新值可配置重放数量可配置缓冲区
核心用途单次数据请求UI 状态管理事件通知生产者 - 消费者模型
发射方式emit()value = ...emit()send()
Compose 推荐用法collectAsStateWithLifecyclecollectAsStateWithLifecycleLaunchedEffect 中 collectcollectAsStateWithLifecycle

四、使用原则与最佳实践

  1. 状态用 StateFlow,事件用 SharedFlow

    • UI 状态(如文本、开关)→ StateFlow;
    • 一次性事件(如弹窗、导航)→ SharedFlow(replay=0,避免重复处理)。
  2. 普通 Flow 仅用于单次请求:如网络接口、数据库查询,避免用于持续更新的场景(否则每次收集都会重复请求)。

  3. 避免 SharedFlow 滥用 replay:事件类 SharedFlow 建议 replay=0,防止新页面接收历史事件导致重复处理。

  4. Compose 中收集注意事项

    • StateFlow:用 collectAsStateWithLifecycle 转为 State,自动重组;
    • SharedFlow:在 LaunchedEffect 中收集,避免重组导致重复订阅;
    • 普通 Flow:用 collectAsStateWithLifecycle,后台自动暂停收集。
  5. 异常处理:所有 Flow 收集时必须加 catch 处理异常,避免崩溃:

flow.catch { e ->
    Log.e("FlowError", "收集失败", e)
    // 兜底值
    emit(-1)
}.collect { ... }

五、核心总结

  1. 普通 Flow:冷流,单次请求首选,无收集则不执行,多收集者独立;
  2. StateFlow:热流,状态管理首选,有初始值、过滤重复值,多收集者共享最新值;
  3. SharedFlow:热流,事件通知首选,可配置重放 / 缓冲区,不过滤重复值;
  4. Channel Flow:底层通道流,适配生产者 - 消费者模型,支持多生产者 / 多消费者。

选择 Flow 类型的核心原则:状态用 StateFlow,事件用 SharedFlow,单次请求用普通 Flow,高频生产用 Channel Flow