Kotlin 协程与 Flow 完全指南
本文档涵盖了 Kotlin 协程和 Flow 的基础知识、示例代码、源码解析以及两者的对比
目录
第一部分:Kotlin 协程
协程基础
什么是协程?
协程(Coroutine)是一种并发编程的方式,允许在单个线程内实现多个任务的协作式多任务。Kotlin 协程通过 suspend 函数实现"挂起和恢复"机制,让异步代码看起来像同步代码一样简洁。
协程的核心优势
- 轻量级:可以在单个线程中运行成千上万个协程
- 内存泄漏更少:使用结构化并发管理协程生命周期
- 内置取消支持:协程可以协作式地取消
- 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()
)
}
调度器工作原理:
- 调度器拦截
Continuation - 使用
dispatch方法将 Runnable 分发到线程池 - 在目标线程执行
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 的特点
- 冷流(Cold Stream):只有在收集时才会开始发射数据
- 响应式:支持多个操作符进行数据转换
- 背压支持:天然支持背压,不需要特殊处理
- 协程友好:与协程深度集成,支持挂起函数
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 工作原理:
flowOn在调用位置之前的所有操作符使用新上下文flowOn之后的所有操作符使用原上下文- 通过缓冲机制实现上下游解耦
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 |
|---|---|---|
| 返回类型 | 单个值 T | 流 Flow<T> |
| 执行时机 | 立即执行 | 收集时执行(冷流) |
| 背压处理 | 需要手动实现(Channel) | 内置支持(buffer、conflate) |
| 操作符 | 基本无操作符 | 丰富的操作符(map、filter 等) |
| 取消 | job.cancel() | collect 协程取消 |
| 异常处理 | try-catch | catch、onCompletion 操作符 |
| 线程切换 | withContext | flowOn |
| 状态管理 | 需要自己实现 | 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 代码的关键。