一、为什么在普通 Flow 中从另一个协程发射会失败?
1. 普通 Flow 是顺序的、同步的
fun simpleFlow(): Flow<Int> = flow {
// 正确:在同一个协程中发射
emit(1)
// 错误:不能在另一个协程中发射
launch(Dispatchers.IO) {
// emit(2) // 编译错误:emit 只能在 flow builder 的协程中调用
}
}
原因:普通 Flow 的 emit() 函数不是线程安全的,且必须在同一个协程上下文中调用。
2. 结构化并发约束
普通 Flow 遵守结构化并发原则:当收集器取消时,整个 flow 构建器块都会被取消。如果允许在外部协程发射,难以追踪和管理所有发射源的取消。
二、ChannelFlow 解决了什么问题?
ChannelFlow 的核心价值:跨协程发射
fun channelFlowExample(): Flow<Int> = channelFlow {
// 可以在多个协程中并发发射
launch {
for (i in 1..5) {
send(i) // 使用 send 而不是 emit
delay(100)
}
}
launch {
for (i in 6..10) {
send(i)
delay(150)
}
}
// 等待所有发射完成
awaitClose()
}
解决的问题:
1. 并发数据源整合
fun mergeMultipleSources(): Flow<String> = channelFlow {
// 多个异步数据源
val sources = listOf(
async { fetchFromNetwork() },
async { readFromDatabase() },
async { getFromCache() }
)
sources.forEach { deferred ->
launch {
val result = deferred.await()
result.forEach { item ->
send(item)
}
}
}
}
2. 生产者-消费者模式
fun producerConsumer(): Flow<Data> = channelFlow {
val channel = this.channel // 获取底层的 Channel
// 生产者协程
launch(Dispatchers.IO) {
while (isActive) {
val data = produceData()
send(data)
}
}
// 另一个生产者
launch(Dispatchers.Default) {
processAndSendResults()
}
}
三、CallbackFlow 解决了什么问题?
CallbackFlow 的特殊用途:桥接回调API
fun listenToLocationUpdates(): Flow<Location> = callbackFlow {
val callback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
result.locations.forEach { location ->
trySend(location) // 非阻塞式发送
}
}
}
// 注册回调
locationClient.requestLocationUpdates(
request,
callback,
Looper.getMainLooper()
)
// 关键:当流被取消时,自动清理资源
awaitClose {
locationClient.removeLocationUpdates(callback)
}
}
解决的问题:
1. 回调API的Flow化
// 传统回调 → Flow 转换
interface EventListener {
fun onEvent(event: Event)
fun onError(error: Throwable)
}
fun listenToEvents(): Flow<Event> = callbackFlow {
val listener = object : EventListener {
override fun onEvent(event: Event) {
trySend(event)
}
override fun onError(error: Throwable) {
close(error)
}
}
registerListener(listener)
awaitClose {
unregisterListener(listener)
}
}
2. 生命周期管理
fun observeAndroidLifecycle(): Flow<Lifecycle.State> = callbackFlow {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_RESUME -> trySend(Lifecycle.State.RESUMED)
Lifecycle.Event.ON_PAUSE -> trySend(Lifecycle.State.STARTED)
// ... 其他状态
}
}
lifecycle.addObserver(observer)
awaitClose {
lifecycle.removeObserver(observer)
}
}
四、底层原理对比
| 特性 | 普通 Flow | ChannelFlow | CallbackFlow |
|---|---|---|---|
| 发射上下文 | 必须相同协程 | 可跨协程 | 可跨协程 |
| 线程安全 | 否 | 是 | 是 |
| 缓冲区 | 无 | 可配置缓冲区 | 可配置缓冲区 |
| 适用场景 | 同步/简单异步 | 并发数据源 | 回调API集成 |
| 取消传播 | 自动 | 手动管理 | 自动清理 |
五、实际应用示例
示例1:WebSocket 连接
fun connectWebSocket(url: String): Flow<Message> = callbackFlow {
val webSocket = WebSocketClient(url, object : WebSocketListener() {
override fun onMessage(message: String) {
trySend(Message.Text(message))
}
override fun onClose(code: Int, reason: String?) {
close(ClosedException(code, reason))
}
})
webSocket.connect()
awaitClose {
webSocket.disconnect()
}
}
示例2:传感器数据流
fun sensorDataFlow(sensor: Sensor): Flow<SensorData> = channelFlow {
val sensorManager = getSensorManager()
// 在主线程注册监听器
launch(Dispatchers.Main) {
sensorManager.registerListener(
{ event ->
launch(Dispatchers.Default) {
// 在后台线程处理并发送
val processed = processSensorEvent(event)
send(processed)
}
},
sensor,
SensorManager.SENSOR_DELAY_NORMAL
)
}
awaitClose {
sensorManager.unregisterListener()
}
}
六、关键要点
1. ChannelFlow:
- 用于需要从多个协程并发发射数据的场景
- 提供了底层的 Channel 作为缓冲区
- 需要手动处理并发和完成信号
2. CallbackFlow:
- 专门用于包装回调式 API
- 自动处理资源清理(通过
awaitClose) - 使用
trySend避免阻塞
3. 为什么需要它们:
- 打破普通 Flow 的"单协程发射"限制
- 支持与现有的异步 API(回调、监听器)集成
- 提供更灵活的生产者-消费者模式
- 更好的资源管理和生命周期控制
选择哪个取决于具体需求:如果是处理并发数据源,用 channelFlow;如果是包装回调 API,用 callbackFlow。