Android-kotlin之Flow基础实战应用

一、Flow是什么?

Flow 是一种用于处理异步数据流的强大工具,它基于协程实现,支持响应式编程模式。

        Flow 是一个冷流(Cold Stream),即只有在被收集(collect)时才会开始执行,类似于 Kotlin 序列(Sequence)的惰性求值特性。它可以异步地发射多个值,支持背压(Backpressure)机制。

核心特点
  • 异步 / 非阻塞:Flow 中的代码可以挂起而不阻塞线程。
  • 支持协程上下文:可以在不同的调度器(如 Dispatchers.IODispatchers.Main)中执行。
  • 处理多个值:与 suspend 函数返回单个值不同,Flow 可以返回多个值。

二、Flow的常用方法

flow 构建器:最基本的构建方式,使用 flow 关键字创建
val numbersFlow = flow {
    for (i in 1..3) {
        delay(100) // 模拟异步操作
        emit(i)    // 发射值
    }
}

// 收集 Flow
launch {
    numbersFlow.collect { value ->
        println(value) // 输出: 1, 2, 3
    }
}
flowOf 静态工厂:创建包含固定值的 Flow
val fruitsFlow = flowOf("Apple", "Banana", "Cherry")
asFlow 扩展函数:将其他类型(如 List、Sequence)转换为 Flow
val listFlow = listOf(1, 2, 3).asFlow()

三、 Flow 的常用操作符

转换操作符
map:对每个元素进行转换:
numbersFlow.map { it * 2 }.collect { println(it) } // 输出: 2, 4, 6
过滤操作符
filter:过滤满足条件的元素:
numbersFlow.filter { it % 2 == 0 }.collect() // 只输出偶数

take:只取前 n 个元素:

numbersFlow.take(2).collect() // 只输出 1, 2
合并操作符

zip:合并两个 Flow 的元素

val lettersFlow = flowOf("A", "B", "C")
numbersFlow.zip(lettersFlow) { num, letter -> "$num-$letter" }
    .collect() // 输出: "1-A", "2-B", "3-C"

combine:合并最新值:

numbersFlow.combine(lettersFlow) { num, letter -> "$num-$letter" }
    .collect() // 输出: "3-A", "3-B", "3-C"
异常处理

catch:捕获 Flow 中的异常

retry:重试失败的 Flow

numbersFlow.retry(3) // 失败时重试3次
生命周期管理

onStart/onCompletion:在 Flow 开始 / 结束时执行操作:

numbersFlow
    .onStart { println("Flow started") }
    .onCompletion { println("Flow completed") }
    .collect()

 cancellable:使 Flow 可被取消:

numbersFlow.cancellable().collect()

四、冷流与热流

1. 基础定义与行为差异
特性 冷流(Cold Flow) 热流(Hot Flow)
数据发射时机 仅在被 collect 时启动数据发射 无论是否有收集者,数据发射独立进行
收集者影响 每个收集者触发独立的数据流(重新执行构建逻辑) 所有收集者共享同一数据流(数据发射与收集者无关)
状态共享 不共享状态,每个收集者拥有独立上下文 共享状态或发射历史,收集者可获取已发射的数据
典型实现 flowflowOfasFlow 等构建的流 StateFlowSharedFlowcallbackFlow

代码示例: 

// 冷流示例:每次 collect 都会重新执行 flow 构建逻辑
val coldFlow = flow {
    println("冷流开始发射数据")
    for (i in 1..3) {
        delay(500)
        emit(i)
    }
}

// 热流示例:StateFlow 始终维护最新值,收集者直接获取当前状态
val hotFlow = MutableStateFlow(0)

// 先更新热流数据,再收集
hotFlow.value = 100
launch {
    hotFlow.collect { println("热流收集值:$it") } // 输出:100
}

// 冷流需要先收集,才会开始发射
launch {
    println("开始收集冷流")
    coldFlow.collect { println("冷流收集值:$it") }
}

2.冷流的底层实现原理 

冷流的核心特性是惰性求值,其底层实现基于以下机制:

flow 构建器的本质
        flow 构建器返回一个 FlowImpl 实例,该实例在 collect 时才会执行 flow 闭包内的代码。闭包中的 emit 操作通过 FlowCollector 接口实现数据发射。

协程上下文绑定
        冷流的执行上下文由 collect 所在的协程作用域决定,每次 collect 都会创建独立的协程执行路径。

冷流的背压处理:

冷流通过操作符实现背压,核心原理是在收集端控制数据接收节奏

buffer() 操作符
创建内部缓冲区(基于 Channel),当发射速度超过收集速度时,未被收集的数据暂存至缓冲区。

conflate() 操作符
丢弃中间未被收集的数据,仅保留最新值,适用于实时数据场景(如传感器数据)。

底层实现代码片段

// flow 构建器的简化实现(Kotlin 标准库)
public fun  flow(block: suspend FlowCollector.() -> Unit): Flow =
    SafeFlow(block) // SafeFlow 是 Flow 的实现类,封装了收集逻辑

// buffer 操作符的核心逻辑
public fun  Flow.buffer(
    capacity: Int = BUFFERED_COLLECTION_DEFAULT_CAPACITY
): Flow = ChannelFlow(capacity) { collector ->
    val channel = Channel(capacity)
    // 发射端将数据存入 Channel
    collect { value -> channel.send(value) }
    // 收集端从 Channel 取出数据
    channel.consumeEach { collector.emit(it) }
}

callbackFlow 是一个 Flow 构建器,用于将回调式 API 转换为 Flow:

  • 适用于传统的事件监听模式(如 Android 的 Player.Listener、Java 的 Future 等)。
  • 通过 Channel 实现背压处理,支持各种背压策略(如 BUFFEREDCONFLATED)。

关键接口 

  • trySend(value)向 Flow 发送值,非阻塞操作,可能因缓冲区满而失败。
  • send(value):挂起函数,阻塞直到值被接收或通道关闭。
  • awaitClose():注册清理逻辑,在 Flow 收集取消时调用。用于资源清理

3.热流的底层实现原理 

StateFlow 是热流的典型实现,核心特性是维护最新状态,其底层原理如下:

  • 数据结构
    MutableStateFlow 继承自 AbstractStateFlow,内部通过 AtomicReference 存储最新值,并使用 SafeMutableStateFlow 封装线程安全操作。
  • 收集者管理
    每个 collect 操作会创建一个 StateFlowCollector,通过 Job 管理协程生命周期,确保状态更新时通知所有活跃收集者。
  • 背压策略
    StateFlow 仅保留最新值,当收集者处理速度慢于发射速度时,旧值会被覆盖(即 conflate 背压策略)。

SharedFlow 支持多收集者共享数据流,底层实现更复杂:

  • 缓冲区机制
    通过 Channel 实现数据缓冲,可配置缓冲区大小(UNLIMITEDBUFFERED 等)。
  • 收集者订阅管理
    使用 MutableSharedFlowImpl 维护收集者列表,通过 BroadcastChannel 实现数据广播。
  • 状态重置逻辑
    当所有收集者取消订阅时,SharedFlow 可选择重置状态(通过 replay 参数配置历史数据保留策略)。
// StateFlow 简化实现
public class MutableStateFlow(initialValue: T) : AbstractStateFlow(initialValue),
    MutableStateFlow {
    private val state = AtomicReference(initialValue)
    
    override val value: T
        get() = state.value
    
    override fun setValue(value: T) {
        state.set(value)
        // 通知所有收集者更新状态
        super.emitValue(value)
    }
    
    // 收集者注册逻辑
    override fun collectSafely(collector: FlowCollector, job: Job) {
        val currentValue = state.value
        // 先发送当前值(热流特性)
        collector.emit(currentValue)
        // 注册状态变更监听
        // ...(省略具体实现)
    }
}

// SharedFlow 核心构造逻辑
public fun  MutableSharedFlow(
    replay: Int = 0,
    extraBufferCapacity: Int = 0,
    onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): MutableSharedFlow = when {
    replay > 0 || extraBufferCapacity > 0 -> {
        // 带缓冲区和历史数据的实现
        MutableSharedFlowImpl(replay, extraBufferCapacity, onBufferOverflow)
    }
    else -> {
        // 无缓冲的简化实现
        NoBufferSharedFlow(onBufferOverflow)
    }
}

 冷热流转换:

通过 stateIn 或 shareIn 操作符实现:

val coldFlow = flow { ... }

// 冷流转热流(StateFlow)
val stateFlow = coldFlow.stateIn(
    scope = CoroutineScope(Dispatchers.Main),
    started = SharingStarted.WhileSubscribed(5000), // 5秒无收集者则停止
    initialValue = 0
)

// 冷流转热流(SharedFlow)
val sharedFlow = coldFlow.shareIn(
    scope = CoroutineScope(Dispatchers.IO),
    replay = 1, // 保留最后1个值
    started = SharingStarted.Eagerly
)
应用场景对比

冷流适用场景:一次性数据加载(如网络请求结果流),按需生成数据(如用户触发事件后的数据流)。

热流适用场景:共享状态管理(如 ViewModel 中的状态流),多组件订阅的实时数据(如传感器数据、网络连接状态)。

五、Flow的背压策略

当 Flow 发射数据的速度快于收集速度时,使用背压策略处理: 

buffer:缓冲数据

numbersFlow.buffer(10) // 缓存10个元素

conflate:只处理最新值:

numbersFlow.conflate()

collectLatest:取消并重新启动收集器:

numbersFlow.collectLatest { value ->
    delay(1000)
    println(value)
}

你可能感兴趣的:(android,kotlin,开发语言)