Kotlin 协程与 Flow 完全指南

15 阅读14分钟

Kotlin 协程与 Flow 完全指南

本文档涵盖了 Kotlin 协程和 Flow 的基础知识、示例代码、源码解析以及两者的对比


目录


第一部分:Kotlin 协程

协程基础

什么是协程?

协程(Coroutine)是一种并发编程的方式,允许在单个线程内实现多个任务的协作式多任务。Kotlin 协程通过 suspend 函数实现"挂起和恢复"机制,让异步代码看起来像同步代码一样简洁。

协程的核心优势

  1. 轻量级:可以在单个线程中运行成千上万个协程
  2. 内存泄漏更少:使用结构化并发管理协程生命周期
  3. 内置取消支持:协程可以协作式地取消
  4. Jetpack 集成:与 Android Jetpack 库深度集成

协程的基本组成

// 协程的三大核心要素
// 1. 协程作用域 (CoroutineScope)
// 2. 协程构建器 (Coroutine Builders: launch, async, runBlocking)
// 3. 协程上下文 (CoroutineContext)

协程核心概念

1. 挂起函数 (Suspend Function)

挂起函数是协程的基础,它只能在协程内部或其他挂起函数中调用。

import kotlinx.coroutines.delay
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.runBlocking

/**
 * 挂起函数示例
 * suspend 关键字标记的函数可以被挂起,而不会阻塞线程
 */
suspend fun fetchData(): String {
    // delay 是一个挂起函数,不会阻塞线程
    delay(1000) // 模拟网络请求延迟
    return "数据加载完成"
}

/**
 * 普通函数无法调用挂起函数
 * fun normalFunction() {
 *     fetchData() // 编译错误:挂起函数只能在协程或挂起函数中调用
 * }

/**
 * 在协程中调用挂起函数
 */
fun main() = runBlocking { // runBlocking 创建一个协程作用域
    val result = fetchData() // 可以调用挂起函数
    println(result)
}

2. 协程作用域 (CoroutineScope)

协程作用域定义了协程的生命周期范围。

import kotlinx.coroutines.*

/**
 * 协程作用域示例
 */
fun main() = runBlocking {
    // launch 在当前作用域内启动一个新协程
    launch {
        delay(200)
        println("Task from launch")
    }

    // async 启动一个新协程并返回 Deferred 结果
    val deferred: Deferred<String> = async {
        delay(100)
        return@async "Task from async"
    }

    println("等待子协程完成...")
    println(deferred.await()) // await() 获取 async 的结果
}

3. 协程上下文 (CoroutineContext)

协程上下文是一组定义协程行为的元素集合。

import kotlinx.coroutines.*

fun main() = runBlocking {
    // CoroutineContext 的四个核心元素:
    // 1. Job:协程的句柄,用于取消和管理
    // 2. Dispatcher:确定协程在哪个线程执行
    // 3. CoroutineName:协程的名称
    // 4. CoroutineExceptionHandler:异常处理器

    // 组合多个上下文元素
    val context: CoroutineContext = CoroutineName("MyCoroutine") + Dispatchers.Default

    launch(context) {
        println("协程运行在: ${Thread.currentThread().name}")
    }
}

4. Job 与协程生命周期

import kotlinx.coroutines.*

fun main() = runBlocking {
    // Job 管理协程的生命周期
    val job = launch {
        repeat(5) { i ->
            delay(500)
            println("协程执行: $i")
        }
    }

    // Job 的状态:New -> Active -> Completing -> Completed
    //           或:New -> Active -> Cancelling -> Cancelled

    println("Job 状态: ${job.isActive}") // true
    println("Job 是否完成: ${job.isCompleted}") // false

    delay(1200)
    job.cancel() // 取消协程

    // 等待协程结束
    job.join()
}

协程示例代码

示例 1:并发执行多个任务

import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

/**
 * 并发执行多个任务
 * 使用 async 启动多个并发任务,然后用 await 等待所有结果
 */
suspend fun fetchUserData(): String {
    delay(500)
    return "用户数据"
}

suspend fun fetchUserOrders(): String {
    delay(800)
    return "订单数据"
}

fun main() = runBlocking {
    val time = measureTimeMillis {
        // 并发执行两个任务
        val deferred1 = async { fetchUserData() }
        val deferred2 = async { fetchUserOrders() }

        // 等待两个任务都完成
        val userData = deferred1.await()
        val userOrders = deferred2.await()

        println("结果: $userData, $userOrders")
    }
    println("总耗时: ${time}ms") // 约 800ms(并行执行)
}

示例 2:异常处理

import kotlinx.coroutines.*
import java.lang.Exception

/**
 * 协程异常处理示例
 */
fun main() = runBlocking {
    // 方式1:使用 try-catch
    try {
        launch {
            delay(100)
            throw ArithmeticException("计算错误")
        }
    } catch (e: Exception) {
        println("捕获异常: ${e.message}")
    }

    // 方式2:使用 CoroutineExceptionHandler
    val handler = CoroutineExceptionHandler { _, exception ->
        println("处理器捕获: ${exception.message}")
    }

    val job = launch(handler) {
        throw IllegalStateException("非法状态")
    }

    job.join()
}

示例 3:超时处理

import kotlinx.coroutines.*
import kotlinx.coroutines.TimeoutCancellationException
import kotlin.system.measureTimeMillis

/**
 * 超时处理示例
 */
fun main() = runBlocking {
    // withTimeout:超时后抛出异常
    try {
        withTimeout(1000) {
            delay(2000)
            println("这行不会执行")
        }
    } catch (e: TimeoutCancellationException) {
        println("操作超时")
    }

    // withTimeoutOrNull:超时后返回 null
    val result = withTimeoutOrNull(1000) {
        delay(2000)
        "完成"
    }
    println("结果: $result") // null
}

示例 4:结构化并发

import kotlinx.coroutines.*

/**
 * 结构化并发示例
 * 父协程会等待所有子协程完成
 */
fun main() = runBlocking {
    launch {
        launch {
            delay(300)
            println("子协程 3 完成")
        }
        launch {
            delay(200)
            println("子协程 2 完成")
        }
        delay(100)
        println("子协程 1 完成")
    }

    // runBlocking 会等待所有子协程完成
    println("主协程等待中...")
}

示例 5:协程调度器 (Dispatchers)

import kotlinx.coroutines.*

/**
 * Dispatchers 决定协程在哪个线程执行
 */
fun main() = runBlocking {
    // Dispatchers.Main:主线程(Android UI 线程)
    // Dispatchers.IO:IO 密集型任务(网络、文件操作)
    // Dispatchers.Default:CPU 密集型任务(计算、排序)
    // Dispatchers.Unconfined:不限制线程,继承调用者线程

    launch(Dispatchers.Default) {
        println("Default: ${Thread.currentThread().name}")
    }

    launch(Dispatchers.IO) {
        println("IO: ${Thread.currentThread().name}")
    }

    launch {
        println("Inherited: ${Thread.currentThread().name}")
    }
}

示例 6:Channel 通信

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel

/**
 * Channel 用于协程间通信
 */
fun main() = runBlocking {
    val channel = Channel<Int>()

    // 生产者协程
    launch {
        for (i in 1..5) {
            delay(100)
            channel.send(i) // 发送数据
            println("发送: $i")
        }
        channel.close() // 关闭通道
    }

    // 消费者协程
    launch {
        for (value in channel) {
            println("接收: $value")
        }
    }
}

示例 7:协程上下文切换

import kotlinx.coroutines.*

/**
 * 使用 withContext 切换协程上下文
 */
suspend fun fetchData(): String = withContext(Dispatchers.IO) {
    // 在 IO 线程执行网络请求
    delay(500)
    return@withContext "从网络获取的数据"
}

fun main() = runBlocking {
    println("主线程: ${Thread.currentThread().name}")

    // withContext 会挂起当前协程,在指定上下文执行,完成后恢复
    val result = fetchData()

    println("结果: $result")
    println("恢复后线程: ${Thread.currentThread().name}")
}

协程源码解析

1. suspend 函数的编译期转换

Kotlin 编译器将 suspend 函数转换为状态机实现。

// 源代码
suspend fun fetchUser(): User {
    val token = getToken()
    val user = getUser(token)
    return user
}

// 编译后的伪代码(简化版)
fun fetchUser(cont: Continuation<User>): Any {
    // 状态标签
    label: {
        when (cont.label) {
            0 -> {
                // 第一次调用,获取 token
                val token = getToken()
                // 保存状态,设置下一次的 label
                cont.label = 1
                // 挂起并返回
                return getTokenSuspended(token, cont)
            }
            1 -> {
                // 恢复后,从挂起点继续
                val token = cont as? Token ?: throw AssertionError()
                val user = getUser(token)
                return user
            }
        }
    }
}

关键点:

  • suspend 函数编译后添加一个 Continuation 参数
  • 使用状态机模式管理挂起点
  • 每个挂起点对应一个状态标签

2. Continuation 接口解析

// Continuation 接口定义
interface Continuation<in T> {
    // 协程的上下文
    val context: CoroutineContext

    // 恢复协程执行,成功时调用
    fun resumeWith(result: Result<T>)
}

// 扩展函数(简化使用)
fun <T> Continuation<T>.resume(value: T)
fun <T> Continuation<T>.resumeWithException(exception: Throwable)

工作原理:

  • Continuation 表示协程的延续(即"接下来要做什么")
  • 挂起时保存 Continuation,恢复时调用 resumeWith
  • 通过 CPS(Continuation-Passing Style)实现协程

3. CoroutineScope 源码解析

/**
 * CoroutineScope 接口定义
 */
public interface CoroutineScope {
    public val coroutineContext: CoroutineContext
}

/**
 * 扩展函数 launch
 */
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    // 合并上下文:新协程继承父作用域的上下文,并加上自定义 context
    val newContext = newCoroutineContext(context)

    // 创建协程
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)

    // 启动协程
    coroutine.start(start, coroutine, block)
    return coroutine
}

关键点:

  • CoroutineScope 只是一个持有 CoroutineContext 的接口
  • launch 创建新的协程并返回 Job
  • 子协程继承父作用域的上下文(结构化并发的基础)

4. Job 源码解析

/**
 * Job 接口定义
 */
public interface Job : CoroutineContext.Element {
    // Job 的状态
    public val isActive: Boolean
    public val isCompleted: Boolean
    public val isCancelled: Boolean

    // 取消协程
    public fun cancel(cause: CancellationException? = null)

    // 等待协程完成(挂起函数)
    public suspend fun join()

    // 携带结果的子接口
    public interface Deferred<out T> : Job {
        public suspend fun await(): T
    }
}

/**
 * Job 状态机转换
 *
 * 状态转换路径:
 * 1. New -> Active -> Completing -> Completed
 * 2. New -> Active -> Cancelling -> Cancelled
 * 3. New -> Active -> Cancelling -> Completed(处理异常后)
 */

Job 状态详解:

  • New:协程已创建但未启动
  • Active:协程正在运行
  • Completing:协程正在完成(等待子协程)
  • Completed:协程已成功完成
  • Cancelling:协程正在取消
  • Cancelled:协程已取消

5. Dispatcher 调度器源码

/**
 * CoroutineDispatcher 抽象类
 */
public abstract class CoroutineDispatcher :
    AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {

    // 调度核心方法:将任务分发到指定线程
    public abstract fun dispatch(context: CoroutineContext, block: Runnable)

    // 恢复执行:可能在同一线程直接恢复
    public fun isDispatchNeeded(context: CoroutineContext): Boolean = true

    // 拦截 continuation,实现调度
    public final override fun <T> interceptContinuation(
        continuation: Continuation<T>
    ): Continuation<T> = DispatchedContinuation(this, continuation)
}

/**
 * Dispatchers.Default 实现
 */
internal object DefaultScheduler : SchedulerCoroutineDispatcher() {
    // 使用 CPU 密集型任务的线程池
    override val corePoolSize: Int
        get() = Runtime.getRuntime().availableProcessors() - 1

    override val maxPoolSize: Int
        get() = corePoolSize * 128

    override val idleWorkerKeepAliveNs: Long
        get() = 60_000_000_000L // 60 秒
}

/**
 * Dispatchers.IO 实现
 */
internal object IoScheduler : ExecutorCoroutineDispatcher() {
    // 使用 IO 密集型任务的线程池
    // 支持更多的线程数(最大 64 个或内核数的倍数)
    override val executor: Executor
        get() = ThreadPoolExecutor(
            corePoolSize, maxPoolSize,
            60L, TimeUnit.SECONDS,
            SynchronousQueue()
        )
}

调度器工作原理:

  1. 调度器拦截 Continuation
  2. 使用 dispatch 方法将 Runnable 分发到线程池
  3. 在目标线程执行 Continuation.resumeWith

6. withContext 实现原理

/**
 * withContext 源码(简化)
 */
public suspend fun <T> withContext(
    context: CoroutineContext,
    block: suspend CoroutineScope.() -> T
): T {
    // 1. 保存旧上下文
    val oldContext = coroutineContext

    // 2. 创建新上下文
    val newContext = newCoroutineContext(oldContext, context)

    // 3. 检查是否需要切换线程
    if (newContext.dispatcher == oldContext.dispatcher) {
        // 同一调度器,直接执行
        return block.startCoroutineCancellable(this, newContext)
    }

    // 4. 切换调度器并执行
    return suspendCoroutineUninterceptedOrReturn { uCont ->
        val dispatcher = newContext.dispatcher
        val dispatch = dispatcher.isDispatchNeeded(newContext)

        if (dispatch) {
            // 分发到新线程
            dispatcher.dispatch(newContext) {
                block.startCoroutineCancellable(uCont.intercepted(), newContext)
            }
        } else {
            // 直接执行
            block.startCoroutineCancellable(uCont.intercepted(), newContext)
        }
    }
}

withContext vs async/await:

  • withContext:挂起当前协程,执行完后恢复(更轻量)
  • async/await:创建新的协程并发执行

7. 协程取消机制

/**
 * 协程取消的核心:协作式取消
 */
public abstract class AbstractCoroutine<in T> ... {
    public override fun cancel(cause: CancellationException?) {
        // 1. 标记为取消状态
        _state.compareAndSet(ACTIVE, COMPLETING)

        // 2. 通知子协程取消
        cancelChildren()

        // 3. 执行取消回调
        handleCancellationException(cause)
    }
}

/**
 * 挂起函数检查取消状态
 */
internal inline fun yieldIfNeed() {
    // 每次挂起恢复时检查
    Thread.currentThread().let { thread ->
        if (thread.isInterrupted) {
            throw CancellationException("Thread interrupted")
        }
    }
}

/**
 * 挂起点自动检查取消
 */
suspend fun delay(time: Long) {
    // delay 内部会检查协程是否被取消
    return suspendCancellableCoroutine { cont ->
        cont.context.ensureActive()
        // ... 实际延迟逻辑
    }
}

取消的关键点:

  • 协程取消是协作式的,需要主动检查
  • 所有挂起函数会自动检查取消状态
  • 使用 ensureActive()yield() 在计算密集代码中检查

第二部分:Kotlin Flow

Flow 基础

什么是 Flow?

Flow 是 Kotlin 协程库中用于处理异步数据流的 API。它代表一个可以异步发出的值序列。

Flow 的特点

  1. 冷流(Cold Stream):只有在收集时才会开始发射数据
  2. 响应式:支持多个操作符进行数据转换
  3. 背压支持:天然支持背压,不需要特殊处理
  4. 协程友好:与协程深度集成,支持挂起函数

Flow 基本结构

// Flow 的三部分:
// 1. 上游(Upstream):数据生产者
// 2. 中间操作符(Intermediate Operators):数据转换
// 3. 终端操作符(Terminal Operator):数据消费者

Flow 核心概念

1. Flow 的基本创建

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 基础示例
 */
fun main() = runBlocking {
    // 创建一个简单的 Flow
    val flow: Flow<Int> = flow {
        // 上游:发射数据
        emit(1)
        emit(2)
        emit(3)
    }

    // 收集 Flow
    flow.collect { value ->
        // 终端操作:消费数据
        println("收到: $value")
    }
}

2. Flow 的冷流特性

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * 冷流特性:只有被 collect 时才会开始发射
 */
fun main() = runBlocking {
    // 创建 Flow(此时不会执行)
    val flow = flow {
        println("开始发射数据")
        emit(1)
        delay(100)
        emit(2)
    }

    println("Flow 已创建")

    delay(1000)

    // 第一次收集
    println("第一次收集")
    flow.collect { println("收集器1: $it") }

    // 第二次收集(会重新执行)
    println("第二次收集")
    flow.collect { println("收集器2: $it") }
}

3. Flow 操作符

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 常用操作符
 */
fun main() = runBlocking {
    flow {
        emit(1)
        emit(2)
        emit(3)
        emit(4)
    }
    // 中间操作符(转换)
    .filter { it % 2 == 0 }      // 过滤偶数
    .map { it * 2 }              // 乘以 2
    .take(2)                     // 只取前两个
    .onEach { println("处理: $it") }
    // 终端操作符(消费)
    .collect { value ->
        println("最终结果: $value")
    }
}

Flow 示例代码

示例 1:基础 Flow 使用

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * 基础 Flow 示例
 */
fun main() = runBlocking {
    // 方式1:使用 flow 构建器
    val numbers = flow {
        for (i in 1..5) {
            delay(100)
            emit(i) // 发射值
        }
    }

    // 收集数据
    numbers.collect { value ->
        println("收到: $value")
    }

    // 方式2:使用 flowOf
    flowOf(1, 2, 3)
        .collect { println("flowOf: $it") }

    // 方式3:使用 asFlow
    listOf(4, 5, 6).asFlow()
        .collect { println("asFlow: $it") }
}

示例 2:Flow 转换操作符

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 转换操作符
 */
fun main() = runBlocking {
    flow {
        emit(1)
        emit(2)
        emit(3)
    }
    .map { it * 2 }              // 转换:[2, 4, 6]
    .filter { it > 2 }           // 过滤:[4, 6]
    .transform { value ->
        emit("前缀: $value")    // 发射多个值
        emit("后缀: $value")
    }
    .collect { println("结果: $it") }
}

示例 3:Flow 限流操作符

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * 限流操作符
 */
fun main() = runBlocking {
    // debounce:防抖,只在静默一段时间后发射最新值
    flow {
        emit(1)
        delay(100)
        emit(2)
        delay(100)
        emit(3)
        delay(1000) // 静默足够长
        emit(4)
    }
    .debounce(500)
    .collect { println("debounce: $it") }

    // sample:采样,按固定时间间隔采样
    flow {
        repeat(10) {
            emit(it)
            delay(100)
        }
    }
    .sample(300)
    .collect { println("sample: $it") }

    // throttleFirst:节流,在时间窗口内只发射第一个值
    flow {
        repeat(10) {
            emit(it)
            delay(100)
        }
    }
    .debounce(50)
    .collect { println("throttle: $it") }
}

示例 4:Flow 的异常处理

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 异常处理
 */
fun main() = runBlocking {
    // 方式1:try-catch
    try {
        flow {
            emit(1)
            throw RuntimeException("错误")
        }
        .collect { println(it) }
    } catch (e: Exception) {
        println("捕获: ${e.message}")
    }

    // 方式2:catch 操作符
    flow {
        emit(1)
        throw IllegalStateException("错误2")
    }
    .catch { e ->
        println("catch 操作符: ${e.message}")
        emit(0) // 发射默认值
    }
    .collect { println("恢复: $it") }

    // 方式3:onCompletion
    flow {
        emit(1)
        emit(2)
    }
    .onCompletion { cause ->
        println("完成,异常: $cause")
    }
    .collect { println(it) }
}

示例 5:Flow 的完成处理

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 完成处理
 */
fun main() = runBlocking {
    flow {
        emit(1)
        emit(2)
        // emit(3)
    }
    .onEach { println("发射: $it") }
    .onEmpty { println("流为空") }        // 流为空时调用
    .onStart { println("开始收集") }       // 收集开始时调用
    .onCompletion { cause ->
        println("收集完成,异常: $cause")  // 收集完成时调用
    }
    .collect { println("收到: $it") }
}

示例 6:Flow 的线程切换

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 线程切换:flowOn
 */
fun main() = runBlocking {
    flow {
        for (i in 1..3) {
            println("上游: ${Thread.currentThread().name}")
            emit(i)
        }
    }
    .flowOn(Dispatchers.Default) // 上游在 Default 线程
    .map { value ->
        println("map: ${Thread.currentThread().name}")
        value * 2
    }
    .flowOn(Dispatchers.IO) // map 在 IO 线程
    .collect { value ->
        println("下游: ${Thread.currentThread().name}, 值: $value")
    }
    // 下游继承主协程的上下文(Main 线程)
}

示例 7:Flow 的缓冲与背压

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 背压处理
 */
fun main() = runBlocking {
    // buffer:缓冲区,上游可以快速发射
    val time = measureTimeMillis {
        flow {
            repeat(5) {
                delay(100)
                emit(it)
                println("发射: $it")
            }
        }
        .buffer(capacity = 3) // 缓冲区大小为 3
        .collect { value ->
            delay(300) // 消费较慢
            println("消费: $value")
        }
    }
    println("总耗时: ${time}ms")

    // conflate:只保留最新的值,中间值会被丢弃
    flow {
        repeat(10) {
            delay(50)
            emit(it)
        }
    }
    .conflate()
    .collect { value ->
        delay(200)
        println("conflate: $value")
    }

    // collectLatest:收到新值时取消之前的处理
    flow {
        repeat(10) {
            delay(50)
            emit(it)
        }
    }
    .collectLatest { value ->
        println("开始处理: $value")
        delay(200)
        println("完成处理: $value")
    }
}

示例 8:Flow 的组合

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 组合操作符
 */
fun main() = runBlocking {
    // zip:组合两个流,等待两者都发射
    val flow1 = flowOf(1, 2, 3).onEach { delay(100) }
    val flow2 = flowOf("A", "B", "C").onEach { delay(150) }

    flow1.zip(flow2) { a, b -> "$a -> $b" }
        .collect { println("zip: $it") }

    // combine:任意流发射时都组合
    flow1.combine(flow2) { a, b -> "$a -> $b" }
        .collect { println("combine: $it") }

    // merge:合并多个流
    merge(
        flowOf(1, 2),
        flowOf(3, 4)
    )
    .collect { println("merge: $it") }

    // flatMapConcat:顺序展平
    flowOf(1, 2, 3)
        .flatMapConcat { value ->
            flowOf("$value-a", "$value-b")
        }
        .collect { println("flatMapConcat: $it") }

    // flatMapMerge:并发展平
    flowOf(1, 2, 3)
        .flatMapMerge { value ->
            flowOf("$value-a", "$value-b")
        }
        .collect { println("flatMapMerge: $it") }

    // flatMapLatest:取消之前的展平
    flowOf(1, 2, 3)
        .onEach { delay(100) }
        .flatMapLatest { value ->
            flow {
                emit(value)
                delay(150)
                emit(value + 10)
            }
        }
        .collect { println("flatMapLatest: $it") }
}

示例 9:StateFlow 与 SharedFlow

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * StateFlow:状态持有流
 * 特点:
 * 1. 始终有值
 * 2. 新订阅者会立即收到最新值
 * 3. 只有值变化时才会发射(去重)
 */
class StateFlowExample {
    private val _state = MutableStateFlow(0)
    val state: StateFlow<Int> = _state

    fun increment() {
        _state.value++
    }
}

/**
 * SharedFlow:事件流
 * 特点:
 * 1. 不持有初始值
 * 2. 可以配置重放数量和缓冲区大小
 * 3. 适合事件场景
 */
class SharedFlowExample {
    private val _events = MutableSharedFlow<Int>(
        replay = 1,              // 重放数量
        onBufferOverflow = BufferOverflow.DROP_OLDEST // 缓冲策略
    )
    val events: SharedFlow<Int> = _events

    suspend fun sendEvent(value: Int) {
        _events.emit(value)
    }
}

fun main() = runBlocking {
    // StateFlow 示例
    val stateFlow = MutableStateFlow(0)

    launch {
        stateFlow.collect { value ->
            println("StateFlow 收到: $value")
        }
    }

    delay(100)
    stateFlow.value = 1
    stateFlow.value = 2
    stateFlow.value = 2 // 重复值不会发射

    // SharedFlow 示例
    val sharedFlow = MutableSharedFlow<Int>(
        replay = 2
    )

    // 先发送一些值
    sharedFlow.emit(1)
    sharedFlow.emit(2)

    delay(100)

    // 新订阅者会收到 replay 的值
    launch {
        sharedFlow.collect { value ->
            println("SharedFlow 收到: $value")
        }
    }

    delay(100)
    sharedFlow.emit(3)
}

示例 10:Flow 的终端操作符

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 终端操作符
 */
fun main() = runBlocking {
    // toList:收集为列表
    val list = flowOf(1, 2, 3).toList()
    println("toList: $list")

    // toSet:收集为集合
    val set = flowOf(1, 2, 2, 3).toSet()
    println("toSet: $set")

    // first:取第一个值
    val first = flowOf(1, 2, 3).first()
    println("first: $first")

    // single:确保只有一个值
    val single = flowOf(42).single()
    println("single: $single")

    // reduce:归约
    val sum = flowOf(1, 2, 3, 4).reduce { acc, value -> acc + value }
    println("reduce sum: $sum")

    // fold:带初始值的归约
    val product = flowOf(1, 2, 3, 4).fold(1) { acc, value -> acc * value }
    println("fold product: $product")

    // collect:收集所有值
    flowOf(1, 2, 3).collect { println("collect: $it") }

    // launchIn:在协程作用域中收集
    flow {
        repeat(3) {
            delay(100)
            emit(it)
        }
    }
    .onEach { println("launchIn: $it") }
    .launchIn(this) // 在 this 作用域中启动
}

Flow 源码解析

1. Flow 接口定义

/**
 * Flow 接口定义
 * Flow 是一个冷流,只有在收集时才会执行
 */
public interface Flow<out T> {
    /**
     * 收集流发出的值
     * @param collector 收集器,接收发出的值
     */
    @Suppress("UNCHECKED_CAST")
    public suspend fun collect(collector: FlowCollector<T>)
}

/**
 * FlowCollector 接口
 */
public interface FlowCollector<in T> {
    /**
     * 发射一个值到流
     */
    public suspend fun emit(value: T)
}

关键点:

  • Flow 接口只有一个 collect 方法
  • Flow 是只读的,不支持发射操作
  • 使用冷流模式:不收集不执行

2. flow 构建器实现

/**
 * flow 构建器实现
 */
public fun <T> flow(
    @BuilderInference block: suspend FlowCollector<T>.() -> Unit
): Flow<T> = SafeFlow(block)

/**
 * SafeFlow 内部实现
 */
private class SafeFlow<T>(
    private val block: suspend FlowCollector<T>.() -> Unit
) : AbstractFlow<T>() {

    /**
     * collectSafely 实现实际的收集逻辑
     */
    override suspend fun collectSafely(collector: FlowCollector<T>) {
        // 调用用户定义的 block,在 collector 上执行
        collector.block()
    }
}

/**
 * AbstractFlow 抽象类
 */
public abstract class AbstractFlow<T> : Flow<T> {

    /**
     * collect 实现
     */
    public final override suspend fun collect(collector: FlowCollector<T>) {
        // 创建收集上下文
        val collectContext = collector as? SafeCollector ?: error("...")

        // 调用子类实现的 collectSafely
        collectSafely(collector)
    }

    /**
     * 子类需要实现的安全收集方法
     */
    protected abstract suspend fun collectSafely(collector: FlowCollector<T>)
}

工作原理:

  • flow { } 创建一个 SafeFlow 实例
  • SafeFlow 保存用户提供的 lambda
  • 调用 collect 时执行 lambda,开始发射数据

3. Flow 操作符链实现

/**
 * 操作符链的核心:每个操作符都返回一个新的 Flow
 */
public inline fun <T, R> Flow<T>.map(
    crossinline transform: suspend (value: T) -> R
): Flow<R> = flow {
    // this 是 FlowCollector<R>(新流的 collector)
    collect { value ->
        // 收集上游的值
        emit(transform(value)) // 转换后发射到新流
    }
}

/**
 * filter 操作符实现
 */
public fun <T> Flow<T>.filter(
    predicate: suspend (T) -> Boolean
): Flow<T> = flow {
    collect { value ->
        if (predicate(value)) {
            emit(value) // 符合条件才发射
        }
    }
}

/**
 * 使用示例
 */
val flow = flowOf(1, 2, 3)
    .map { it * 2 }     // 返回新 Flow1
    .filter { it > 2 }  // 返回新 Flow2

// 等价于:
val flow2 = flow {
    flowOf(1, 2, 3).collect { value ->
        val transformed = value * 2
        if (transformed > 2) {
            emit(transformed)
        }
    }
}

关键点:

  • 每个操作符创建新的 Flow 实例
  • 操作符内部通过 collect 收集上游
  • 转换后通过 emit 发射到下游
  • 形成操作符链:collect 链式调用

4. flowOn 线程切换原理

/**
 * flowOn 实现线程切换
 */
public fun <T> Flow<T>.flowOn(
    context: CoroutineContext
): Flow<T> = flow {
    // 创建一个调度器
    val dispatcher = context[ContinuationInterceptor] as? CoroutineDispatcher

    // 在上游使用新上下文收集
    coroutineScope {
        // 切换到指定上下文
        withContext(context) {
            // 在新线程中收集上游
            this@flow.collect { value ->
                // 发射到下游(下游在原来的线程)
                emit(value)
            }
        }
    }
}

/**
 * 更精确的实现(简化版)
 */
internal class FlowOnFlow<T>(
    private val upstream: Flow<T>,
    private val context: CoroutineContext
) : Flow<T> {

    override suspend fun collect(collector: FlowCollector<T>) {
        // 上游使用新上下文
        upstream.collect(object : FlowCollector<T> {
            override suspend fun emit(value: T) {
                // 切换上下文发射
                withContext(context) {
                    collector.emit(value)
                }
            }
        })
    }
}

flowOn 工作原理:

  1. flowOn 在调用位置之前的所有操作符使用新上下文
  2. flowOn 之后的所有操作符使用原上下文
  3. 通过缓冲机制实现上下游解耦

5. 背压处理机制

/**
 * buffer 操作符实现
 */
public fun <T> Flow<T>.buffer(
    capacity: Int = BUFFERED
): Flow<T> = channelFlow {
    // 创建 Channel 作为缓冲区
    val channel = Channel<T>(capacity)

    // 上游协程:快速发射到 Channel
    launch {
        collect { value ->
            channel.send(value)
        }
        channel.close()
    }

    // 下游:从 Channel 接收
    channel.consumeEach { value ->
        send(value)
    }
}

/**
 * conflate 操作符:只保留最新值
 */
public fun <T> Flow<T>.conflate(): Flow<T> = buffer(CONFLATED)

/**
 * collectLatest 操作符:收到新值取消旧的处理
 */
public fun <T> Flow<T>.collectLatest(
    action: suspend (value: T) -> Unit
) = flow {
    // 当前任务的 Job
    var currentJob: Job? = null

    collect { value ->
        // 取消之前的任务
        currentJob?.cancel()
        // 启动新任务
        currentJob = launch {
            action(value)
        }
    }
}.collect()

背压处理策略:

  • buffer:缓冲区满时挂起上游
  • conflate:缓冲区满时丢弃最旧的值
  • collectLatest:缓冲区满时取消当前处理

6. SharedFlow 实现原理

/**
 * SharedFlow 接口
 */
public interface SharedFlow<out T> : Flow<T> {
    val replayCache: List<T>
}

/**
 * MutableSharedFlow 实现
 */
public interface MutableSharedFlow<T> : SharedFlow<T>, FlowCollector<T> {
    override suspend fun emit(value: T)
    fun tryEmit(value: T): Boolean
}

/**
 * SharedFlow 内部实现(简化)
 */
internal class SharedFlowImpl<T>(
    private val replayCapacity: Int,
    private val bufferCapacity: Int,
    private val onBufferOverflow: BufferOverflow
) : MutableSharedFlow<T> {

    // 订阅者列表
    private val collectors = mutableListOf<SharedFlowCollector>()

    // 缓冲区
    private val buffer = ArrayDeque<Any?>()

    // 重放缓存
    private val replayCache = ArrayDeque<Any?>()

    override suspend fun emit(value: T) {
        synchronized(this) {
            // 添加到重放缓存
            if (replayCapacity > 0) {
                replayCache.addLast(value)
                if (replayCache.size > replayCapacity) {
                    replayCache.removeFirst()
                }
            }

            // 发射给所有订阅者
            collectors.forEach { collector ->
                collector.emit(value)
            }
        }
    }

    override suspend fun collect(collector: FlowCollector<T>) {
        val sharedCollector = SharedFlowCollector(collector)
        collectors.add(sharedCollector)

        // 发送重放缓存
        replayCache.forEach { value ->
            collector.emit(value as T)
        }

        try {
            // 等待新值
            sharedCollector.wait()
        } finally {
            collectors.remove(sharedCollector)
        }
    }
}

SharedFlow 工作原理:

  • 维护一个订阅者列表
  • 每个 emit 广播给所有订阅者
  • 使用 replayCache 缓存最近的值

7. StateFlow 实现原理

/**
 * StateFlow 接口
 */
public interface StateFlow<out T> : SharedFlow<T> {
    val value: T
}

/**
 * MutableStateFlow 实现(简化)
 */
public interface MutableStateFlow<T> : StateFlow<T>, MutableSharedFlow<T> {
    override var value: T
}

/**
 * StateFlow 内部实现
 */
public class StateFlowImpl<T>(
    initialValue: T
) : MutableStateFlow<T> {

    // 当前值(volatile 保证可见性)
    @Volatile
    override var value: T = initialValue

    // 订阅者集合
    private val collectors = mutableSetOf<StateFlowCollector>()

    override suspend fun emit(newValue: T) {
        val oldValue = value
        value = newValue

        // 只有值变化时才通知订阅者
        if (oldValue != newValue) {
            synchronized(collectors) {
                collectors.forEach { collector ->
                    collector.emit(newValue)
                }
            }
        }
    }

    override suspend fun collect(collector: FlowCollector<T>) {
        val stateCollector = StateFlowCollector(collector)

        // 立即发送当前值
        collector.emit(value)

        synchronized(collectors) {
            collectors.add(stateCollector)
        }

        try {
            // 等待新值
            stateCollector.wait()
        } finally {
            synchronized(collectors) {
                collectors.remove(stateCollector)
            }
        }
    }
}

StateFlow 特点:

  • 始终持有当前值
  • 新订阅者立即收到当前值
  • 值相同时不重复发射

8. Flow 的异常处理机制

/**
 * catch 操作符实现
 */
public fun <T> Flow<T>.catch(
    action: suspend FlowCollector<T>.(cause: Throwable) -> Unit
): Flow<T> = flow {
    try {
        collect { value ->
            emit(value)
        }
    } catch (e: Throwable) {
        // 在收集器上执行异常处理
        action(e)
    }
}

/**
 * onCompletion 操作符实现
 */
public fun <T> Flow<T>.onCompletion(
    action: suspend FlowCollector<T>.(cause: Throwable?) -> Unit
): Flow<T> = flow {
    try {
        collect { value ->
            emit(value)
        }
    } finally {
        // 无论成功还是异常都执行
        action(null)
    }
}

/**
 * retryWhen 操作符:重试机制
 */
public fun <T> Flow<T>.retryWhen(
    predicate: suspend (cause: Throwable, attempt: Long) -> Boolean
): Flow<T> = flow {
    var attempt = 0L
    var shallRetry: Boolean

    do {
        shallRetry = false
        try {
            collect { value ->
                emit(value)
            }
        } catch (e: Throwable) {
            if (predicate(e, attempt)) {
                attempt++
                shallRetry = true
            } else {
                throw e
            }
        }
    } while (shallRetry)
}

第三部分:协程与 Flow 对比

核心差异

1. 设计理念

特性协程 (Coroutine)Flow
用途执行单个异步任务处理异步数据流
返回值单个结果多个值的序列
执行模式热启动(创建即运行)冷启动(收集时才运行)
模型函数式(输入 -> 输出)流式(连续的数据流)

2. 代码对比

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * 协程 vs Flow 对比
 */
fun main() = runBlocking {
    // ========================================
    // 场景1:获取单个结果
    // ========================================

    // 使用协程:适合单个异步操作
    suspend fun fetchUser(): User {
        delay(100)
        return User("张三")
    }

    val user = fetchUser() // 一次调用,一次结果
    println("协程结果: $user")

    // 使用 Flow:即使单个结果也用流
    val userFlow: Flow<User> = flow {
        emit(User("张三"))
    }

    userFlow.collect { user ->
        println("Flow 结果: $user")
    }

    // ========================================
    // 场景2:处理多个值
    // ========================================

    // 使用协程:需要返回 List
    suspend fun fetchUsers(): List<User> {
        delay(100)
        return listOf(User("张三"), User("李四"))
    }

    val users = fetchUsers()
    users.forEach { println("协程批量: $it") }

    // 使用 Flow:自然地处理多个值
    fun userFlow(): Flow<User> = flow {
        repeat(10) { i ->
            delay(50)
            emit(User("用户$i"))
        }
    }

    userFlow().collect { user ->
        println("Flow 流式: $user")
    }

    // ========================================
    // 场景3:实时数据更新
    // ========================================

    // 协程方式:需要轮询或回调
    suspend fun pollForUpdates(): List<User> {
        // 需要定时轮询
        delay(1000)
        return fetchUsers()
    }

    // Flow 方式:自然地推送更新
    fun userUpdates(): Flow<User> = callbackFlow {
        // 模拟实时更新
        repeat(10) { i ->
            delay(500)
            trySend(User("更新$i"))
        }
        close()
    }

    userUpdates().collect { update ->
        println("实时更新: $update")
    }
}

适用场景对比

协程适合的场景

import kotlinx.coroutines.*

/**
 * 协程最佳实践场景
 */
object CoroutineUseCases {

    // 1. 网络请求(单次)
    suspend fun fetchUserProfile(userId: String): Profile {
        return withContext(Dispatchers.IO) {
            // 网络调用
            Profile("用户", 25)
        }
    }

    // 2. 数据库操作(单次)
    suspend fun saveUser(user: User) {
        withContext(Dispatchers.IO) {
            // 数据库插入
            database.insert(user)
        }
    }

    // 3. 并发执行多个独立任务
    suspend fun loadDashboard(): Dashboard {
        coroutineScope {
            val profile = async { fetchUserProfile("123") }
            val orders = async { fetchUserOrders("123") }
            val notifications = async { fetchNotifications() }

            Dashboard(profile.await(), orders.await(), notifications.await())
        }
    }

    // 4. 批量处理
    suspend fun processBatch(items: List<Item>): List<Result> {
        return withContext(Dispatchers.Default) {
            items.map { item ->
                processItem(item) // CPU 密集型计算
            }
        }
    }
}

Flow 适合的场景

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * Flow 最佳实践场景
 */
object FlowUseCases {

    // 1. 实时数据流(WebSocket、传感器)
    fun websocketUpdates(): Flow<Message> = callbackFlow {
        val socket = WebSocket { message ->
            trySend(message) // 实时推送
        }

        awaitClose { socket.close() }
    }

    // 2. UI 事件流
    fun clickEvents(view: View): Flow<ClickEvent> = callbackFlow {
        val listener = View.OnClickListener { event ->
            trySend(ClickEvent(event))
        }

        view.setOnClickListener(listener)
        awaitClose { view.setOnClickListener(null) }
    }

    // 3. 分页加载
    fun paginatedNews(): Flow<Article> = flow {
        var page = 1
        while (true) {
            val articles = fetchArticlesPage(page)
            articles.forEach { emit(it) }
            if (articles.isEmpty()) break
            page++
        }
    }

    // 4. 数据库变化监听
    fun observeUsers(): Flow<User> = callbackFlow {
        val observer = object : DatabaseObserver<User> {
            override fun onChange(data: User) {
                trySend(data)
            }
        }

        database.registerObserver(observer)
        awaitClose { database.unregisterObserver(observer) }
    }

    // 5. 搜索防抖
    fun search(queryFlow: Flow<String>): Flow<Result> =
        queryFlow
            .debounce(300)                      // 防抖
            .filter { it.length >= 2 }          // 最小长度
            .distinctUntilChanged()             // 去重
            .map { query -> performSearch(query) }
            .catch { e -> emit(Result.Error(e)) }

    // 6. StateFlow:UI 状态管理
    class ViewModel {
        private val _uiState = MutableStateFlow(UiState.Idle)
        val uiState: StateFlow<UiState> = _uiState

        fun loadData() {
            _uiState.value = UiState.Loading
            viewModelScope.launch {
                val result = fetchData()
                _uiState.value = UiState.Success(result)
            }
        }
    }

    // 7. SharedFlow:事件总线
    object EventBus {
        private val _events = MutableSharedFlow<Event>()
        val events: SharedFlow<Event> = _events

        suspend fun sendEvent(event: Event) {
            _events.emit(event)
        }
    }
}

性能对比

1. 内存开销

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * 协程 vs Flow 性能对比
 */
fun main() = runBlocking {
    // 协程:一次性加载所有数据到内存
    val time1 = measureTimeMillis {
        val data = loadAllData() // 返回 List<10000条>
        processList(data)
    }
    println("协程(一次性加载): ${time1}ms")

    // Flow:流式处理,低内存占用
    val time2 = measureTimeMillis {
        dataFlow()
            .take(100) // 只处理前100条
            .collect { item ->
                processItem(item)
            }
    }
    println("Flow(流式处理): ${time2}ms")
}

// 模拟大数据集
suspend fun loadAllData(): List<Int> {
    return (1..10000).toList()
}

fun dataFlow(): Flow<Int> = flow {
    repeat(10000) { emit(it) }
}

2. 背压处理

/**
 * 背压处理对比
 */
fun main() = runBlocking {
    // 协程:需要手动实现背压
    launch {
        val channel = Channel<Int>(capacity = 10)
        // 生产者
        launch {
            repeat(1000) { i ->
                channel.send(i) // 满时挂起
            }
            channel.close()
        }
        // 消费者
        launch {
            for (value in channel) {
                delay(100) // 慢速消费
                println("消费: $value")
            }
        }
    }

    // Flow:内置背压支持
    flow {
        repeat(1000) { i ->
            emit(i) // 自动处理背压
        }
    }
    .buffer(10) // 缓冲区
    .conflate() // 或只保留最新值
    .collect { value ->
        delay(100)
        println("Flow: $value")
    }
}

总结对比表

维度协程 (Coroutine)Flow
返回类型单个值 TFlow<T>
执行时机立即执行收集时执行(冷流)
背压处理需要手动实现(Channel)内置支持(buffer、conflate)
操作符基本无操作符丰富的操作符(map、filter 等)
取消job.cancel()collect 协程取消
异常处理try-catchcatch、onCompletion 操作符
线程切换withContextflowOn
状态管理需要自己实现StateFlow、SharedFlow
适用场景单次异步任务连续数据流、实时更新
学习曲线简单相对复杂
性能单次操作更轻量流式处理更高效

选择建议

/**
 * 选择指南
 */
object ChoiceGuide {

    // ✅ 使用协程的场景:
    // 1. 单次网络请求
    suspend fun getUser(id: String): User

    // 2. 数据库 CRUD 操作
    suspend fun insertUser(user: User)

    // 3. 文件读写
    suspend fun readFile(path: String): ByteArray

    // 4. 并发执行多个独立任务
    suspend fun loadAll(): Data = coroutineScope {
        val a = async { loadA() }
        val b = async { loadB() }
        Data(a.await(), b.await())
    }

    // ✅ 使用 Flow 的场景:
    // 1. 实时数据流
    fun observeMessages(): Flow<Message>

    // 2. 分页加载
    fun loadPages(): Flow<Item>

    // 3. 搜索框防抖
    fun search(query: Flow<String>): Flow<Result>

    // 4. UI 状态管理
    val uiState: StateFlow<UiState>

    // 5. 事件总线
    val events: SharedFlow<Event>

    // 6. 数据库变化监听
    fun observeUsers(): Flow<User>

    // 7. 定时任务
    fun ticker(): Flow<Unit> = flow {
        while (true) {
            emit(Unit)
            delay(1000)
        }
    }

    // ✅ 两者结合使用:
    suspend fun loadAndUpdate() {
        viewModelScope.launch {
            // 协程:加载数据
            val users = fetchUsers()

            // Flow:发送更新
            usersFlow.emitAll(users.asFlow())
        }
    }
}

参考资源

官方文档

推荐阅读


结语:协程和 Flow 是 Kotlin 异步编程的两大支柱。协程适合处理单个异步任务,而 Flow 适合处理异步数据流。理解它们的差异并根据场景选择合适的工具,是编写高效 Kotlin 代码的关键。