第五部分:Flow 进阶原理
第13章:Flow 背压机制深度对比
13.1 Flow (冷流):灵活但需手动配置的背压
文案总结:
冷流每次收集时从头开始执行,适合数据转换管道,但需要手动管理背压问题。当生产速度 > 消费速度时,需要选择合适的背压策略。
13.1.1 背压三剑客对比分析
对比表格:
| 策略 | 原理 | 适用场景 | 数据丢失情况 |
|---|---|---|---|
| buffer | 建立缓冲区,生产消费并行 | 文件下载、批量处理 | 不丢失 |
| conflate | 丢弃中间值,只保留最新 | UI状态更新、传感器数据 | 丢弃中间值 |
| collectLatest | 新值到来时取消当前处理 | 搜索建议、可取消操作 | 丢弃未完成值 |
代码示例:
kotlin
// 1. buffer示例:建立缓冲区
flow {
repeat(5) { i ->
delay(50)
emit(i)
}
}.buffer(2) // 容量为2的缓冲区
.collect { delay(100); println(it) }
// 2. conflate示例:只保留最新
flow {
repeat(5) { i ->
delay(30)
emit(i)
}
}.conflate() // 丢弃中间值
.collect { delay(100); println(it) }
// 3. collectLatest示例:可取消处理
flow {
repeat(5) { i ->
delay(50)
emit(i)
}
}.collectLatest { // 新值到来取消当前
println("开始: $it")
delay(200)
println("完成: $it")
}
场景选择指南:
- 实时监控:conflate(只关心最新)
- 数据备份:buffer(不能丢失)
- 用户输入:collectLatest(可取消)
13.2 StateFlow:永不挂起,丢弃中间值的策略
文案总结:
StateFlow是热流,保存当前状态,自动去重。快速更新时丢弃中间值,emit(value)永不挂起,适合UI状态管理。
代码示例:
kotlin
// StateFlow特性演示
val stateFlow = MutableStateFlow(0)
// 生产者快速更新
launch {
repeat(10) {
stateFlow.value = it // 永不挂起,中间值被丢弃
delay(10)
}
}
// 消费者慢速收集
launch {
stateFlow.collect {
println("收到: $it")
delay(100)
}
}
13.3 SharedFlow:高度可配,支持挂起或丢弃
文案总结:
SharedFlow是热流,无当前状态概念,可配置缓冲区大小和背压策略(SUSPEND或DROP)。适合事件总线。
代码示例:
kotlin
// SharedFlow配置示例
val sharedFlow = MutableSharedFlow<String>(
replay = 1, // 新订阅者获取最新1个值
extraBufferCapacity = 10, // 额外缓冲区
onBufferOverflow = BufferOverflow.DROP_OLDEST // 满时丢弃最旧
)
// 发射可能挂起(如果缓冲区满且策略为SUSPEND)
launch {
sharedFlow.emit("事件")
}
13.4 性能陷阱与优化
13.4.1 flatMap的滥用问题
文案总结:
flatMap每次发射创建新流,导致内存和性能问题。应使用map + flattenMerge控制并发数。
代码示例:
kotlin
// ❌ 错误:频繁创建流
flowOf("a", "b", "c")
.flatMapConcat { search(it) }
// ✅ 优化:控制并发
flowOf("a", "b", "c")
.map { search(it) }
.flattenMerge(concurrency = 2) // 限制并发数
13.4.2 线程切换成本分析
文案总结:
每个flowOn创建新协程,增加上下文切换开销。应合并连续flowOn调用。
代码示例:
kotlin
// ❌ 频繁切换
flow { emit(1) }
.flowOn(Dispatchers.IO)
.map { it * 2 }
.flowOn(Dispatchers.Default) // 不必要的切换
// ✅ 合并切换
flow {
withContext(Dispatchers.IO) {
emit(1)
}
}.flowOn(Dispatchers.IO) // 只切换一次
13.4.3 内存泄漏排查
文案总结:
未取消的协程导致内存泄漏。使用lifecycleScope,及时取消协程,避免GlobalScope。
代码示例:
kotlin
class SafeViewModel : ViewModel() {
fun collectSafely() {
viewModelScope.launch { // ✅ 随ViewModel清理
flow.collect {
// 处理数据
}
}
}
}
13.4.4 CPU使用率优化
文案总结:
避免繁忙循环,添加延迟,使用批处理减少操作次数。
代码示例:
kotlin
// ❌ 繁忙循环,高CPU
flow {
while (true) {
emit(data)
}
}
// ✅ 添加延迟,降低CPU
flow {
while (true) {
emit(data)
delay(16) // ~60FPS
}
}
13.5 场景分析:如何为不同场景选择最优背压策略?
决策树:
-
数据能否丢失?
- 不能 → buffer
- 能 → 继续
-
只关心最新吗?
- 是 → conflate
- 否 → collectLatest
-
操作可取消吗?
- 是 → collectLatest
- 否 → 无特殊策略
代码示例:
kotlin
// 搜索场景:collectLatest
searchFlow.collectLatest { query ->
val results = searchApi(query)
updateUI(results)
}
// 下载场景:buffer
downloadFlow.buffer(3) // 并发下载3个文件
// 状态更新:conflate
sensorDataFlow.conflate() // 只更新最新读数
第14章:Channel:Flow的底层通信管道
14.1 Channel vs. Flow:为何Google推荐优先使用Flow?
对比表格:
| 特性 | Channel | Flow (推荐) |
|---|---|---|
| 编程模型 | 命令式 | 声明式 |
| 背压支持 | 基本 | 丰富策略 |
| 操作符 | 少 | 丰富(map、filter等) |
| 内存安全 | 易泄漏 | 冷流更安全 |
代码示例:
kotlin
// Flow优先
flow { emit(1); emit(2) }
.map { it * 2 }
.collect { println(it) }
// Channel特定场景
val channel = Channel<Int>()
launch { channel.send(1) }
launch { println(channel.receive()) }
14.2 Channel的适用场景:协程间的安全通信
文案总结:
Channel适合精确控制背压、工作队列、协程间双向通信。
代码示例:
kotlin
// 工作队列模式
val taskChannel = Channel<Task>()
repeat(3) { workerId ->
launch {
for (task in taskChannel) {
processTask(task)
}
}
}
// 请求-响应模式
val requestChannel = Channel<Request>()
val responseChannel = Channel<Response>()
第15章:Flow内部实现探秘
15.1 emit-collect的调用链路与SafeCollector
文案总结:
SafeCollector包装原始收集器,确保emit在正确上下文调用,防止线程安全问题。
代码示例:
kotlin
// 简化流程
flow {
emit(1) // → SafeCollector → 原始collector
}.collect { println(it) }
15.2 flowOn()如何实现上下文切换
文案总结:
flowOn创建新协程,在新上下文中收集,通过SafeCollector切回原上下文发射。
代码示例:
kotlin
flow { emit(1) }
.flowOn(Dispatchers.IO) // 创建IO协程收集
.collect { // 在主线程收集
println(it)
}
15.3 StateFlow如何通过CAS操作保证并发安全
文案总结:
StateFlow使用AtomicReference和CAS操作保证并发更新安全,自动去重。
代码示例:
kotlin
// 简化CAS操作
var value = 0
fun update(newValue: Int) {
while (true) {
val current = value
if (current == newValue) return // 去重
if (compareAndSet(current, newValue)) break
}
}
第16章:性能优化与自定义操作符
16.1 性能优化技巧
检查清单:
✅ 使用lifecycleScope/viewModelScope
✅ 合并flowOn调用
✅ 避免flatMap滥用
✅ 及时取消协程
✅ 使用合适的缓冲区大小
代码示例:
kotlin
// 综合优化
viewModelScope.launch {
dataSource()
.flowOn(Dispatchers.IO) // 合并IO操作
.buffer(50) // 合理缓冲区
.collect { updateUI(it) }
}
16.2 自定义Flow操作符
文案总结:
通过扩展函数创建自定义操作符,封装业务逻辑,提高代码复用性。
代码示例:
kotlin
// 自定义防抖操作符
fun <T> Flow<T>.debounceFirst(timeout: Long): Flow<T> = flow {
var lastEmitTime = 0L
collect { value ->
val now = System.currentTimeMillis()
if (now - lastEmitTime >= timeout) {
emit(value)
lastEmitTime = now
}
}
}
// 使用
flow { emit(1); emit(2) }
.debounceFirst(100)
.collect()
📊 第六部分:测试与质量保障
第17章:测试你的Flow
17.1 使用kotlinx-coroutines-test和Turbine库
文案总结:
测试Flow需要特殊工具,因为Flow是异步的。Turbine提供Flow测试DSL。
代码示例:
kotlin
dependencies {
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4")
testImplementation("app.cash.turbine:turbine:0.12.1")
}
17.2 单元测试:测试普通Flow、StateFlow与SharedFlow
代码示例:
kotlin
@Test
fun `测试普通Flow`() = runTest {
flowOf(1, 2, 3).test {
assertEquals(1, awaitItem())
assertEquals(2, awaitItem())
assertEquals(3, awaitItem())
awaitComplete()
}
}
@Test
fun `测试StateFlow`() = runTest {
val stateFlow = MutableStateFlow(0)
// 测试初始值
assertEquals(0, stateFlow.value)
// 测试更新
stateFlow.value = 1
assertEquals(1, stateFlow.value)
}
@Test
fun `测试SharedFlow`() = runTest {
val sharedFlow = MutableSharedFlow<Int>()
// 收集流
val values = mutableListOf<Int>()
val job = launch {
sharedFlow.collect { values.add(it) }
}
// 发射值
sharedFlow.emit(1)
sharedFlow.emit(2)
// 等待收集完成
advanceUntilIdle()
// 验证
assertEquals(listOf(1, 2), values)
job.cancel()
}
17.3 集成测试与UI测试策略
文案总结:
集成测试验证多个组件协作,UI测试验证Flow是否正确更新界面。
代码示例:
kotlin
// ViewModel集成测试
@Test
fun `测试ViewModel与Flow集成`() = runTest {
val viewModel = MyViewModel()
// 触发操作
viewModel.fetchData()
// 验证状态变化
viewModel.uiState.test {
assertEquals(Loading, awaitItem())
val success = awaitItem() as Success
assertEquals(3, success.data.size)
}
}
// Compose UI测试
@Test
fun `测试Compose UI更新`() = runComposeTest {
val viewModel = MyViewModel()
setContent {
val state by viewModel.state.collectAsState()
Text(text = state)
}
// 验证初始状态
onNodeWithText("初始").assertExists()
// 更新状态并验证
viewModel.updateState("新状态")
onNodeWithText("新状态").assertExists()
}
第18章:调试与监控
18.1 Coroutine Debugger与日志技巧
文案总结:
使用协程调试器查看协程状态,添加CoroutineName便于日志跟踪。
代码示例:
kotlin
// 添加协程名称
launch(CoroutineName("数据加载")) {
flow.collect {
println("${coroutineContext[CoroutineName]?.name}: 收到 $it")
}
}
// 调试技巧
val flow = flow {
println("Flow开始执行")
emit(1)
println("Flow继续执行")
}.onEach {
println("中间处理: $it")
}
18.2 性能监控与分析
文案总结:
使用Android Profiler监控内存、CPU、网络,添加自定义监控点。
代码示例:
kotlin
// 简单性能监控
class FlowMonitor {
fun <T> monitor(flow: Flow<T>, name: String): Flow<T> = flow {
val startTime = System.currentTimeMillis()
var count = 0
flow.collect { value ->
count++
emit(value)
}
val duration = System.currentTimeMillis() - startTime
println("[$name] 处理 $count 项,耗时 ${duration}ms")
}
}
// 使用
flow { emit(1); emit(2) }
.monitor("测试流")
.collect()
📋 快速参考表
背压策略速查
| 场景 | 策略 | 代码 |
|---|---|---|
| 完整数据 | buffer | .buffer(50) |
| UI更新 | conflate | .conflate() |
| 搜索建议 | collectLatest | .collectLatest { } |
| 事件总线 | SharedFlow | MutableSharedFlow() |
| 状态管理 | StateFlow | MutableStateFlow() |
测试代码模板
kotlin
// Flow测试模板
@Test
fun `Flow基本测试`() = runTest {
flow { /* 构建数据 */ }
.test {
// 验证每个值
assertEquals(expected1, awaitItem())
assertEquals(expected2, awaitItem())
// 验证完成
awaitComplete()
}
}
这个完整指南涵盖了Flow的核心概念、性能优化、测试策略和调试技巧,每个部分都提供了简洁的文案总结和实用的代码示例。
第19章:Flow 十大反模式清单
📉 19.1 生命周期泄漏:launchWhenX 的陷阱与正确解决方案
问题描述:
使用 launchWhenStarted、launchWhenResumed 等函数会导致协程在生命周期状态变化时重复启动和停止,造成资源浪费和状态不一致。
错误代码:
kotlin
// ❌ 反模式:使用 launchWhenX
class LeakyViewModel : ViewModel() {
init {
lifecycleScope.launchWhenStarted {
flow.collect { updateUI(it) } // 每次恢复都会重新收集
}
}
}
正确解决方案:
kotlin
// ✅ 正确模式:使用 repeatOnLifecycle
class SafeViewModel : ViewModel() {
fun observeWithLifecycle(lifecycle: Lifecycle) {
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
flow.collect { updateUI(it) } // 自动取消和重启
}
}
}
}
📉 19.2 过度使用 flatMap:性能杀手与替代方案
问题描述:
flatMapConcat 每次发射都创建新流,导致大量协程和内存开销,尤其是在高频数据流中。
错误代码:
kotlin
// ❌ 反模式:每个值都创建新流
flow {
emit("query1")
emit("query2")
}.flatMapConcat { query ->
networkRequestFlow(query) // 每次发射都创建新流
}
正确解决方案:
kotlin
// ✅ 正确模式:控制并发数
flow {
emit("query1")
emit("query2")
}.map { query ->
networkRequestFlow(query)
}.flattenMerge(concurrency = 2) // 限制并发数
📉 19.3 错误的重试策略:无限重试与指数退避的正确使用
问题描述:
简单重试或无限重试可能导致死循环或过多资源消耗。
错误代码:
kotlin
// ❌ 反模式:无限重试
flow {
emit(data)
}.retry { true } // 永远重试
// ❌ 反模式:立即重试
.retry(3) // 立即重试3次,可能导致雪崩
正确解决方案:
kotlin
// ✅ 正确模式:指数退避重试
fun <T> Flow<T>.retryWithBackoff(
maxRetries: Int = 3,
initialDelay: Long = 1000
): Flow<T> = flow {
var currentDelay = initialDelay
var retryCount = 0
collect { value -> emit(value) }
}.catch { e ->
if (retryCount++ < maxRetries) {
delay(currentDelay)
currentDelay *= 2 // 指数退避
emitAll(this@retryWithBackoff) // 重新收集
} else {
throw e
}
}
📉 19.4 线程切换混乱:flowOn 多次调用的副作用
问题描述:
多个 flowOn 调用创建多个协程层,增加上下文切换开销。
错误代码:
kotlin
// ❌ 反模式:不必要的多次切换
flow {
emit(1) // IO线程
}
.flowOn(Dispatchers.IO)
.map { it * 2 } // Default线程
.flowOn(Dispatchers.Default)
.filter { it > 0 } // IO线程
.flowOn(Dispatchers.IO)
正确解决方案:
kotlin
// ✅ 正确模式:合并线程切换
flow {
// 所有IO操作集中处理
withContext(Dispatchers.IO) {
emit(1)
// 其他IO操作...
}
}
.flowOn(Dispatchers.IO) // 只切换一次
.map { it * 2 }
.filter { it > 0 }
📉 19.5 状态管理不当:MutableStateFlow 暴露给UI层
问题描述:
直接将 MutableStateFlow 暴露给UI层,允许UI直接修改状态,破坏单向数据流。
错误代码:
kotlin
// ❌ 反模式:MutableStateFlow 公开
class BadViewModel : ViewModel() {
val count = MutableStateFlow(0) // UI可以直接修改
fun increment() {
count.value++ // ViewModel应该控制所有状态更新
}
}
正确解决方案:
kotlin
// ✅ 正确模式:暴露只读 StateFlow
class GoodViewModel : ViewModel() {
private val _count = MutableStateFlow(0)
val count: StateFlow<Int> = _count.asStateFlow() // 只读
fun increment() {
_count.value++ // 只有ViewModel可以修改
}
}
// UI层只能收集,不能修改
viewModel.count.collect { updateUI(it) }
📉 19.6 事件重复消费:SharedFlow 配置错误导致事件被多次处理
问题描述:
SharedFlow 配置不当可能导致事件被多个观察者重复消费,或新订阅者收到旧事件。
错误代码:
kotlin
// ❌ 反模式:replay 配置不当
val events = MutableSharedFlow<Event>(
replay = 10 // 新订阅者会收到10个旧事件
)
// ❌ 反模式:多个观察者都处理相同事件
events.collect { handleEvent(it) } // 观察者1
events.collect { handleEvent(it) } // 观察者2:重复处理
正确解决方案:
kotlin
// ✅ 正确模式:根据场景配置 SharedFlow
// 场景1:事件只消费一次
val singleConsumerEvents = MutableSharedFlow<Event>(
replay = 0, // 不重播给新订阅者
extraBufferCapacity = 1
)
// 场景2:每个订阅者独立处理
val broadcastEvents = MutableSharedFlow<Event>().broadcastIn(viewModelScope)
// 使用唯一标识避免重复处理
events.distinctUntilChanged { it.id }.collect { handleEvent(it) }
📉 19.7 背压处理错误:错误选择 buffer、conflate、collectLatest
问题描述:
背压策略选择不当导致数据丢失、性能问题或用户体验不佳。
错误代码:
kotlin
// ❌ 反模式:搜索使用 buffer(用户看到过时结果)
searchFlow.buffer().collect { showResults(it) }
// ❌ 反模式:传感器数据使用 collectLatest(频繁取消导致抖动)
sensorFlow.collectLatest { updateChart(it) }
// ❌ 反模式:下载进度使用 conflate(丢失中间进度)
downloadFlow.conflate().collect { updateProgress(it) }
正确解决方案:
kotlin
// ✅ 正确模式:根据数据特性选择策略
// 搜索:collectLatest(用户需要最新结果)
searchFlow.collectLatest { showLatestResults(it) }
// 传感器:conflate(只关心最新读数)
sensorFlow.conflate().collect { updateLatestReading(it) }
// 下载:buffer(需要完整进度)
downloadFlow.buffer().collect { updateAllProgress(it) }
📉 19.8 资源未释放:Flow 收集未取消导致的资源泄漏
问题描述:
Flow 收集未正确取消,导致后台持续运行,消耗资源。
错误代码:
kotlin
// ❌ 反模式:未管理收集协程
class LeakyService {
init {
// 收集协程未保存引用
flow.collect { process(it) } // 无法取消
}
// ❌ 使用 GlobalScope
GlobalScope.launch {
flow.collect { process(it) } // 生命周期不受控
}
}
正确解决方案:
kotlin
// ✅ 正确模式:管理收集生命周期
class SafeService {
private var collectionJob: Job? = null
fun startCollecting() {
collectionJob?.cancel() // 取消之前的收集
collectionJob = lifecycleScope.launch {
flow.collect { process(it) }
}
}
fun stopCollecting() {
collectionJob?.cancel()
collectionJob = null
}
override fun onDestroy() {
super.onDestroy()
collectionJob?.cancel() // 确保清理
}
}
📉 19.9 测试不充分:缺少对 Flow 超时、异常场景的测试
问题描述:
只测试正常流程,忽略异常、超时、边界条件等场景。
错误代码:
kotlin
// ❌ 反模式:只测试正常情况
@Test
fun testFlow() = runTest {
flowOf(1, 2, 3).test {
assertEquals(1, awaitItem())
assertEquals(2, awaitItem())
assertEquals(3, awaitItem())
// 缺少超时、异常测试
}
}
正确解决方案:
kotlin
// ✅ 正确模式:全面测试各种场景
@Test
fun `测试Flow正常情况`() = runTest {
flowOf(1, 2, 3).test {
assertEquals(1, awaitItem())
assertEquals(2, awaitItem())
assertEquals(3, awaitItem())
awaitComplete()
}
}
@Test
fun `测试Flow超时`() = runTest {
// 测试超时行为
assertTimeout(1000) {
slowFlow.test { /* ... */ }
}
}
@Test
fun `测试Flow异常`() = runTest {
flow { throw RuntimeException("错误") }
.test {
assertFailsWith<RuntimeException> { awaitItem() }
}
}
@Test
fun `测试Flow空流`() = runTest {
emptyFlow<Int>().test {
awaitComplete() // 应该立即完成
}
}
📉 19.10 架构设计缺陷:混淆状态与事件的边界
问题描述:
将状态(State)和事件(Event)混用同一个 Flow,导致逻辑混乱。
错误代码:
kotlin
// ❌ 反模式:状态和事件混用
class ConfusedViewModel : ViewModel() {
private val _uiState = MutableStateFlow<UiModel>()
val uiState: StateFlow<UiModel> = _uiState
fun showMessage(text: String) {
// 将事件作为状态更新
_uiState.value = _uiState.value.copy(
message = text,
showMessage = true
)
// 需要手动重置状态
delay(3000)
_uiState.value = _uiState.value.copy(
showMessage = false
)
}
}
正确解决方案:
kotlin
// ✅ 正确模式:状态和事件分离
class ClearViewModel : ViewModel() {
// 状态:当前UI状态
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState
// 事件:一次性事件
private val _events = MutableSharedFlow<UiEvent>()
val events: SharedFlow<UiEvent> = _events.asSharedFlow()
fun showMessage(text: String) {
// 发送事件
viewModelScope.launch {
_events.emit(ShowMessageEvent(text))
}
}
fun updateData(data: Data) {
// 更新状态
_uiState.value = _uiState.value.copy(
data = data,
isLoading = false
)
}
}
// 事件定义
sealed class UiEvent {
data class ShowMessageEvent(val text: String) : UiEvent()
object NavigateToNextScreen : UiEvent()
}
// UI层处理
viewModel.events.collect { event ->
when (event) {
is ShowMessageEvent -> showToast(event.text)
NavigateToNextScreen -> navigate()
}
}
📋 反模式检查清单
| 反模式 | 症状 | 修复方案 |
|---|---|---|
| 生命周期泄漏 | 重复收集、资源浪费 | 使用 repeatOnLifecycle |
| 过度使用 flatMap | 内存过高、性能差 | 使用 flattenMerge 控制并发 |
| 错误重试策略 | 无限循环、资源耗尽 | 实现指数退避重试 |
| 线程切换混乱 | 上下文切换开销大 | 合并 flowOn 调用 |
| 状态管理不当 | UI可以直接修改状态 | 暴露只读 StateFlow |
| 事件重复消费 | 同一事件处理多次 | 合理配置 SharedFlow |
| 背压处理错误 | 数据丢失或响应慢 | 根据场景选择策略 |
| 资源未释放 | 后台持续运行 | 管理收集协程生命周期 |
| 测试不充分 | 生产环境出现意外 | 增加边界条件测试 |
| 架构设计缺陷 | 状态事件混淆 | 分离 StateFlow 和 SharedFlow |
🛠️ 代码质量检查工具
kotlin
// 简单的反模式检测器
object FlowAntiPatternDetector {
fun analyzeFlow(flow: Flow<*>): List<String> {
val warnings = mutableListOf<String>()
// 检测 flatMap 滥用
if (flow.toString().contains("flatMapConcat")) {
warnings.add("⚠️ 检测到 flatMapConcat,考虑使用 flattenMerge")
}
// 检测多个 flowOn
val flowOnCount = flow.toString().count { it == "flowOn" }
if (flowOnCount > 1) {
warnings.add("⚠️ 检测到 $flowOnCount 个 flowOn,考虑合并")
}
return warnings
}
}
// 使用示例
val warnings = FlowAntiPatternDetector.analyzeFlow(myFlow)
warnings.forEach { println(it) }
🔧 最佳实践速查
kotlin
// 模板:安全的数据流架构
class BestPracticeViewModel : ViewModel() {
// 1. 状态管理:只读暴露
private val _state = MutableStateFlow(initialState)
val state: StateFlow<State> = _state.asStateFlow()
// 2. 事件管理:一次性事件
private val _events = MutableSharedFlow<Event>(
replay = 0,
extraBufferCapacity = 10
)
val events: SharedFlow<Event> = _events.asSharedFlow()
// 3. 安全的流收集
private var collectionJobs = mutableMapOf<String, Job>()
fun startFlowCollection(name: String, flow: Flow<*>) {
collectionJobs[name]?.cancel()
collectionJobs[name] = viewModelScope.launch {
flow.collect { /* 处理 */ }
}
}
fun stopFlowCollection(name: String) {
collectionJobs[name]?.cancel()
collectionJobs.remove(name)
}
// 4. 生命周期管理
override fun onCleared() {
collectionJobs.values.forEach { it.cancel() }
super.onCleared()
}
}