deepseek Kotlin Flow 全面详解

deepseek总结的文档,十分靠谱!微调了少量内容。

1. Flow 基础概念

1.1 什么是 Flow

Flow 是 Kotlin 协程库中的异步数据流处理工具,类似于 RxJava 的 Observable,但更简洁、与协程深度集成。

1.2 Flow 的特点

  • 冷流(Cold Stream):有收集者时才执行
  • 可取消的:基于协程的取消机制
  • 背压感知:自动处理生产消费速度不匹配
  • 丰富的操作符:类似集合操作但支持异步

2. Flow 的创建方式

2.1 基础创建方法

kotlin 复制代码
// 1. flow{} 构建器 - 最常用
fun simpleFlow(): Flow<Int> = flow {
    for (i in 1..3) {
        delay(100) // 可以调用挂起函数
        emit(i)    // 发射值
    }
}

// 2. asFlow() 扩展 - 从集合转换
fun collectionToFlow(): Flow<Int> = listOf(1, 2, 3).asFlow()

// 3. flowOf() - 从固定值创建
fun fixedFlow(): Flow<Int> = flowOf(1, 2, 3)

// 4. channelFlow - 更灵活的构建器
fun channelFlowExample(): Flow<Int> = channelFlow {
    send(1)
    withContext(Dispatchers.IO) {
        send(2) // 可以在不同上下文发送
    }
    send(3)
    close()
}

2.2 channelFlow{} vs flow{}

channelFlow和flow是Kotlin协程中处理数据流的两种方式,主要区别体现在以下几个方面:

  1. 数据流特性
    flow‌是冷数据流,只有在订阅者开始收集数据时才会触发数据生产,且每个订阅者会独立获得完整的数据序列。它类似于电梯,只有调用collect时才启动数据生产,结束后立即停止。
    channelFlow‌是热数据流的一种扩展,允许在数据生产时切换协程上下文,并内置缓冲区(默认64)。它更像地铁自动扶梯,数据生产独立于消费存在。
  2. 上下文限制
    flow‌严格要求在同一个协程上下文中发射数据,不允许通过withContext切换调度器。
    channelFlow‌通过send方法支持跨协程发送数据,内部使用Channel实现多协程并发生产。允许使用withContext。
  3. 缓冲机制
    flow‌需要显式调用.buffer()操作符添加缓冲功能。
    channelFlow‌天然具备缓冲区(也可通过.buffer()配置大小),且支持异步合并多个流(如通过launch并发收集)。
  4. 生命周期控制
    flow‌的生命周期与收集操作绑定,收集结束即终止。
    channelFlow‌可通过awaitClose保持通道开放,直到显式关闭。
    典型使用场景
    flow‌适用于单次数据提供场景(如数据库查询,API请求)。
    channelFlow‌适合事件合并、跨协程数据生产或需要背压控制的场景(如合并多个API响应)。

3. Flow 的终端操作符

3.1 收集操作符

kotlin 复制代码
suspend fun terminalOperators() {
    val numberFlow = (1..5).asFlow()
    
    // 1. collect - 基本收集
    numberFlow.collect { value -> println("收集: $value") }
    
    // 2. launchIn - 在指定作用域启动收集
    numberFlow
        .onEach { println("launchIn: $it") }
        .launchIn(CoroutineScope(Dispatchers.IO))
    
    // 3. toList/toSet - 转换为集合
    val list = numberFlow.toList()
    val set = numberFlow.toSet()
    println("转换为List: $list")
    
    // 4. first/firstOrNull - 获取第一个元素
    val first = numberFlow.first()
    val firstOrNull = emptyFlow<Int>().firstOrNull()
    println("第一个元素: $first")
    
    // 5. single/singleOrNull - 期望只有一个元素
    val single = flowOf(42).single()
    println("唯一元素: $single")
    
    // 6. count - 计数
    val count = numberFlow.count()
    println("元素数量: $count")
    
    // 7. reduce/fold - 聚合操作
    val sum = numberFlow.reduce { acc, value -> acc + value }
    val sumWithStart = numberFlow.fold(10) { acc, value -> acc + value }
    println("累加和: $sum, 带初始值的和: $sumWithStart")
}

4. Flow 的中间操作符

4.1 转换操作符

kotlin 复制代码
suspend fun transformOperators() {
    val flow = (1..3).asFlow()
    
    // 1. map - 转换每个元素
    flow.map { it * it }.collect { println("平方: $it") }
    
    // 2. transform - 更灵活的转换,可以发射多个值
    flow.transform { value ->
        if (value % 2 == 1) {
            emit(value)
            emit(value * 10)
        }
    }.collect { println("transform: $it") }
    
    // 3. mapLatest - 取消之前的转换,只处理最新的
    flow.mapLatest { value ->
        delay(100) // 模拟耗时操作
        "映射后的$value"
    }.collect { println("mapLatest: $it") }
}

4.2 过滤操作符

kotlin 复制代码
suspend fun filterOperators() {
    val flow = (1..10).asFlow()
    
    // 1. filter - 条件过滤
    flow.filter { it % 2 == 0 }.collect { println("偶数: $it") }
    
    // 2. filterNot - 反向过滤
    flow.filterNot { it > 5 }.collect { println("小于等于5: $it") }
    
    // 3. filterIsInstance - 类型过滤
    flowOf(1, "hello", 2, "world", 3)
        .filterIsInstance<String>()
        .collect { println("字符串: $it") }
    
    // 4. take - 取前n个
    flow.take(3).collect { println("前3个: $it") }
    
    // 5. drop - 丢弃前n个
    flow.drop(5).collect { println("丢弃前5个后: $it") }
    
    // 6. distinctUntilChanged - 去重连续重复
    flowOf(1, 1, 2, 2, 3, 3, 1)
        .distinctUntilChanged()
        .collect { println("去重连续重复: $it") }
}

4.3 组合操作符

kotlin 复制代码
suspend fun combinationOperators() {
    val flow1 = flowOf("A", "B", "C")
    val flow2 = flowOf(1, 2, 3)
    
    // 1. zip - 一对一组合
    flow1.zip(flow2) { a, b -> "$a$b" }
        .collect { println("zip: $it") } // A1, B2, C3
    
    // 2. combine - 最新值组合
    val numbers = flowOf(1, 2, 3).onEach { delay(100) }
    val letters = flowOf("A", "B", "C").onEach { delay(150) }
    
    numbers.combine(letters) { number, letter -> "$number$letter" }
        .collect { println("combine: $it") } // 1A, 2A, 2B, 3B, 3C
    
    // 3. merge - 合并多个流
    merge(flow1, flow2.map { it.toString() })
        .collect { println("merge: $it") } // A, B, C, 1, 2, 3
    
    // 4. flatMapConcat - 顺序展开
    flow1.flatMapConcat { value -> 
        flowOf("$value1", "$value2") 
    }.collect { println("flatMapConcat: $it") } // A1, A2, B1, B2, C1, C2
    
    // 5. flatMapMerge - 并发展开
    flow1.flatMapMerge { value ->
        flow {
            delay(100)
            emit("$value-快速")
            delay(200)
            emit("$value-慢速")
        }
    }.collect { println("flatMapMerge: $it") }
    
    // 6. flatMapLatest - 最新值展开
    flow1.flatMapLatest { value ->
        flow {
            emit("开始$value")
            delay(200) // 如果新值到来,会取消这个流
            emit("完成$value")
        }
    }.collect { println("flatMapLatest: $it") }
}

4.4 异常处理操作符

kotlin 复制代码
suspend fun exceptionHandling() {
    val flow = flow {
        emit(1)
        throw RuntimeException("模拟错误")
        emit(2) // 不会执行
    }
    
    // 1. catch - 捕获异常
    flow.catch { e -> 
        println("捕获异常: ${e.message}")
        emit(-1) // 可以恢复发射
    }.collect { println("catch: $it") }
    
    // 2. retry - 重试
    var attempt = 0
    flow.retry(2) { cause ->
        attempt++
        println("第${attempt}次重试,原因: ${cause.message}")
        attempt < 2 // 条件重试
    }.catch { e -> 
        emit(999) 
    }.collect { println("retry: $it") }
    
    // 3. retryWhen - 更灵活的重试
    flow.retryWhen { cause, attempt ->
        if (attempt < 3 && cause is RuntimeException) {
            delay(1000 * attempt)
            true
        } else {
            false
        }
    }.catch { e -> 
        println("最终失败: ${e.message}")
    }.collect { println("retryWhen: $it") }
}

4.5 回调操作符

kotlin 复制代码
suspend fun callbackOperators() {
    val flow = (1..3).asFlow()
    
    // 1. onEach - 每个元素处理前的回调
    flow.onEach { println("即将发射: $it") }
        .collect { println("收集到: $it") }
    
    // 2. onStart - 流开始前的回调
    flow.onStart { 
        println("流开始执行")
        emit(0) // 可以提前发射值
    }.collect { println("onStart: $it") }
    
    // 3. onCompletion - 流完成后的回调
    flow.onCompletion { cause ->
        if (cause == null) {
            println("流正常完成")
        } else {
            println("流异常完成: ${cause.message}")
        }
    }.collect { println("onCompletion: $it") }
    
    // 4. onEmpty - 流为空时的回调
    emptyFlow<Int>().onEmpty { 
        println("流为空,发射默认值")
        emit(-1)
    }.collect { println("onEmpty: $it") }
}

5. 上下文和调度

5.1 flowOn 操作符

kotlin 复制代码
suspend fun flowOnExample() {
    // flowOn 影响上游操作的上下文
    flow {
        // 这个块在 IO 线程执行
        println("发射线程: ${Thread.currentThread().name}")
        emit(1)
        emit(2)
    }
    .flowOn(Dispatchers.IO) // 指定上游上下文
    .map { 
        // 这个map在默认上下文执行(因为后面没有flowOn)
        println("映射线程: ${Thread.currentThread().name}")
        it * 2 
    }
    .flowOn(Dispatchers.Default) // 可以再次改变上游上下文
    .collect { 
        // 收集在调用协程的上下文
        println("收集线程: ${Thread.currentThread().name}, 值: $it")
    }
}

5.2 buffer 操作符 - 背压处理

kotlin 复制代码
suspend fun bufferOperators() {
    val slowFlow = flow {
        for (i in 1..3) {
            delay(100) // 模拟慢生产者
            emit(i)
            println("发射: $i")
        }
    }
    
    println("=== 无缓冲 ===")
    val time1 = measureTimeMillis {
        slowFlow.collect { value ->
            delay(300) // 模拟慢消费者
            println("处理: $value")
        }
    }
    println("总时间: ${time1}ms")
    
    println("=== 有缓冲 ===")
    val time2 = measureTimeMillis {
        slowFlow
            .buffer() // 添加缓冲,生产消费可以并发
            .collect { value ->
                delay(300)
                println("处理: $value")
            }
    }
    println("总时间: ${time2}ms")
    
    // 其他缓冲策略
    slowFlow.conflate() // 合并,只处理最新值
        .collect { println("conflate: $it") }
    
    slowFlow.collectLatest { value -> // 取消慢的处理,处理最新值
        println("开始处理: $value")
        delay(400)
        println("完成处理: $value") // 可能被取消
    }
}

6. 共享流(SharedFlow 和 StateFlow)

6.1 shareIn - 冷流转热流

api为:

kotlin 复制代码
fun <T> Flow<T>.shareIn(
    scope: CoroutineScope,
    started: SharingStarted,
    replay: Int = 0
): SharedFlow<T>
  • 不需要初始值
  • 返回 SharedFlow,不能直接访问当前值
  • 可以配置重放数量(replay)
  • 适合事件、通知、一次性操作
示例1:
kotlin 复制代码
val notifications: SharedFlow<Notification> = notificationFlow
    .shareIn(
        scope = viewModelScope,
        started = SharingStarted.Eagerly,
        replay = 1  // 新订阅者收到最近1个通知
    )

// 不能直接访问当前值,只能通过收集
notifications.collect { notification ->
    showToast(notification.message)
}
示例2:
kotlin 复制代码
class DataRepository {
    // 冷流:每次收集都会重新执行
    private val dataFlow = flow {
        println("执行数据获取")
        emit(fetchDataFromNetwork())
    }
    
    // 使用 shareIn 转换为热流
    private val sharedFlow = dataFlow.shareIn(
        scope = CoroutineScope(Dispatchers.IO),
        started = SharingStarted.WhileSubscribed(
            stopTimeoutMillis = 5000, // 最后一个订阅者取消后5秒停止
            replayExpirationMillis = 0 // 立即过期重放数据
        ),
        replay = 1 // 新订阅者重放1个最新值
    )
    
    fun getData(): Flow<String> = sharedFlow
    
    private suspend fun fetchDataFromNetwork(): String {
        delay(1000)
        return "网络数据 ${System.currentTimeMillis()}"
    }
}

suspend fun shareInExample() {
    val repository = DataRepository()
    
    // 第一个订阅者
    val job1 = launch {
        repository.getData().collect { println("订阅者1: $it") }
    }
    
    delay(500)
    
    // 第二个订阅者 - 共享同一个数据流
    val job2 = launch {
        repository.getData().collect { println("订阅者2: $it") }
    }
    
    delay(2000)
    job1.cancel()
    job2.cancel()
}

6.2 stateIn - 转换为状态流

api为:

kotlin 复制代码
fun <T> Flow<T>.stateIn(
    scope: CoroutineScope,
    started: SharingStarted,
    initialValue: T
): StateFlow<T>
  • 必须有初始值
  • 返回 StateFlow,可以通过 .value 访问当前状态
  • 自动去重连续相同的值
  • 适合表示UI状态、应用状态
kotlin 复制代码
class CounterViewModel : ViewModel() {
    private val tickFlow = flow {
        var count = 0
        while (true) {
            delay(1000)
            emit(count++)
        }
    }
    
    // 使用 stateIn 转换为状态流
    val counterState = tickFlow.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = 0
    )
}

suspend fun stateInExample() {
    val viewModel = CounterViewModel()
    
    // 状态流总是有当前值
    viewModel.counterState.collect { value ->
        println("当前计数: $value")
    }
}

对于普通flow{} 我们通过上述代码来转换。而对于多个Stateflow组合,combine之后会退化为普通flow,需要重新stateIn变成StateFlow:

kotlin 复制代码
val _uiState = MutableStateFlow<UiState>(UiState.Initial)
val bState = MutableStateFlow<BState>(BState.Inital)

val uiState: StateFlow<UiState> = _uiState.combine(bState) { ui, bState->
	xxxx
}.stateIn(scope, SharingStarted.WhileSubscribed(5000), _uiState.value)

6.3 launchIn - 在指定作用域启动

kotlin 复制代码
suspend fun launchInExample() {
    val eventFlow = flow {
        repeat(5) {
            delay(500)
            emit("事件$it")
        }
    }
    
    val scope = CoroutineScope(Dispatchers.IO + CoroutineName("MyScope"))
    
    // 使用 launchIn 在指定作用域启动收集
    val job = eventFlow
        .onEach { event -> 
            println("处理事件: $event 在线程: ${Thread.currentThread().name}")
        }
        .launchIn(scope) // 返回Job可以取消
    
    delay(2000)
    println("取消收集")
    job.cancel()
}

6.4 StateFlow vs flow{}

StateFlow 特性:

  • 热流(Hot Flow):不管有没有收集者,都会存在并发射数据
  • 有状态 :始终持有当前值,可以通过 .value 访问
  • 可变的:可以直接更新值
  • 重复值抑制:默认不会发射相同的连续值
  • 多播:多个收集者共享同一个状态

flow{}特性:

  • 冷流(Cold Flow):只有在被收集时才会执行
  • 无状态:不持有当前值
  • 不可变的 :只能通过 emit 发射值
  • 每次收集重新执行:每个收集者都会触发流的重新执行
  • 单播:每个收集者获得独立的流执行
特性 StateFlow flow{}
类型 热流 冷流
状态 有状态,持有当前值 无状态
可变性 可变,可直接更新 不可变
执行时机 立即存在 收集时执行
重复收集 共享相同执行 每次重新执行
使用场景 状态管理、UI状态 异步操作、数据转换

使用场景举例:

kotlin 复制代码
// MutableStateFlow: UI 状态管理
class ViewModel {
    private val _uiState = MutableStateFlow<UiState>(Loading)
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()
    
    fun loadData() {
        _uiState.value = Success(data)
    }
}

// flow{} 网络请求、数据库查询等一次性操作
fun fetchUserData(userId: String): Flow<User> = flow {
    val user = apiService.getUser(userId)
    emit(user)
}

// flow{} 复杂的数据转换
fun processData(input: Flow<Int>): Flow<String> = flow {
    input.collect { number ->
        val processed = heavyProcessing(number)
        emit(processed.toString())
    }
}

6.5 shareIn vs stateIn

stateInshareIn 都是用于将冷流转换为热流的操作符,但它们在行为和用途上有重要区别。

基本区别

特性 stateIn shareIn
返回类型 StateFlow SharedFlow
初始值 必须提供 可选(通过 replay)
状态特性 始终有当前值 可能没有值(如果没有发射过)
重复值抑制 自动抑制连续相同值 默认不抑制,可配置
使用场景 状态管理 事件广播、数据共享
SharingStarted 策略

两者都使用相同的启动策略:

1. SharingStarted.Eagerly
kotlin 复制代码
// 立即启动,不管有没有订阅者
started = SharingStarted.Eagerly
2. SharingStarted.Lazily
kotlin 复制代码
// 在第一个订阅者出现时启动
started = SharingStarted.Lazily
3. SharingStarted.WhileSubscribed
kotlin 复制代码
// 有订阅者时启动,无订阅者时停止
// 可以配置超时和重放过期
started = SharingStarted.WhileSubscribed(
    stopTimeoutMillis = 0,
    replayExpirationMillis = 0
)

// 保留5秒,防止快速重新订阅
started = SharingStarted.WhileSubscribed(5000)
实际使用场景对比
stateIn 适合的场景:
kotlin 复制代码
class UserViewModel : ViewModel() {
    // UI状态 - 使用 stateIn
    val uiState: StateFlow<UiState> = userRepository
        .getUserStream()
        .map { user -> 
            UiState.Success(user) 
        }
        .catch { e -> 
            emit(UiState.Error(e.message ?: "Unknown error"))
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = UiState.Loading
        )
}
shareIn 适合的场景:
kotlin 复制代码
class EventBus {
    // 事件总线 - 使用 shareIn
    private val _events = MutableSharedFlow<Event>()
    
    val events: SharedFlow<Event> = _events
        .shareIn(
            scope = CoroutineScope(Dispatchers.Default),
            started = SharingStarted.Eagerly,
            replay = 0
        )
    
    fun sendEvent(event: Event) {
        _events.tryEmit(event)
    }
}

// 一次性操作结果
val searchResults: SharedFlow<SearchResult> = searchFlow
    .shareIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(),
        replay = 1
    )
选择指南
使用 stateIn 当:
  • 你需要表示状态(有当前值)
  • 你需要直接访问当前值(通过 .value
  • 你希望自动去重连续相同的值
  • 用于UI状态、数据状态管理
使用 shareIn 当:
  • 你需要广播事件或通知
  • 不需要直接访问当前值
  • 需要控制重放数量
  • 用于一次性操作、事件总线、消息传递
小结:
  • stateInStateFlow → 用于状态,有当前值,自动去重
  • shareInSharedFlow → 用于事件,无当前值,可配置重放

根据你的具体需求选择合适的操作符,大多数UI状态管理场景使用 stateIn,而事件处理使用 shareIn

7. 高级特性

7.1 自定义操作符

kotlin 复制代码
// 自定义过滤操作符
fun <T> Flow<T>.filterWithLog(predicate: (T) -> Boolean): Flow<T> = flow {
    collect { value ->
        if (predicate(value)) {
            println("过滤通过: $value")
            emit(value)
        } else {
            println("过滤拒绝: $value")
        }
    }
}

// 自定义转换操作符
fun Flow<Int>.runningSum(): Flow<Int> = flow {
    var sum = 0
    collect { value ->
        sum += value
        emit(sum)
    }
}

suspend fun customOperators() {
    (1..5).asFlow()
        .filterWithLog { it % 2 == 0 }
        .runningSum()
        .collect { println("运行和: $it") }
}

7.2 复杂组合示例

kotlin 复制代码
suspend fun complexFlowExample() {
    // 模拟用户输入流
    val userInputs = flowOf("A", "B", "C", "D", "E")
        .onEach { delay(200) } // 模拟用户输入间隔
    
    // 模拟网络请求流
    fun simulateNetworkRequest(input: String): Flow<String> = flow {
        delay(500) // 模拟网络延迟
        emit("响应: $input")
    }
    
    userInputs
        .onStart { println("开始监听用户输入") }
        .onEach { println("用户输入: $it") }
        .flatMapMerge(concurrency = 3) { input -> // 并发处理最多3个请求
            simulateNetworkRequest(input)
                .onStart { println("开始请求: $input") }
                .catch { e -> emit("错误: ${e.message}") }
        }
        .onEach { println("收到响应: $it") }
        .buffer() // 防止背压
        .catch { e -> println("流异常: ${e.message}") }
        .onCompletion { println("流完成") }
        .collect()
}

8. 实际应用案例

8.1 搜索建议功能

kotlin 复制代码
class SearchViewModel : ViewModel() {
    private val searchQuery = MutableStateFlow("")
    
    val searchResults = searchQuery
        .debounce(300) // 防抖300ms
        .filter { it.length >= 3 } // 至少3个字符
        .distinctUntilChanged() // 查询相同时不重复搜索
        .flatMapLatest { query -> // 取消之前的搜索
            performSearch(query)
                .catch { e -> emit(emptyList()) }
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = emptyList()
        )
    
    fun onSearchQueryChanged(query: String) {
        searchQuery.value = query
    }
    
    private fun performSearch(query: String): Flow<List<String>> = flow {
        // 模拟网络搜索
        delay(1000)
        val results = listOf("${query}结果1", "${query}结果2", "${query}结果3")
        emit(results)
    }
}

8.2 实时数据更新

kotlin 复制代码
class StockMonitor {
    private val stockPrices = MutableSharedFlow<StockPrice>(
        replay = 10, // 重放最近10个价格
        extraBufferCapacity = 50
    )
    
    // 模拟实时价格更新
    fun startMonitoring() {
        CoroutineScope(Dispatchers.IO).launch {
            var price = 100.0
            while (true) {
                delay(1000)
                price += (Math.random() - 0.5) * 10 // 随机波动
                stockPrices.emit(StockPrice("AAPL", price, System.currentTimeMillis()))
            }
        }
    }
    
    fun getPriceUpdates(): Flow<StockPrice> = stockPrices
    
    // 价格变化率计算
    fun getPriceChanges(): Flow<Double> = stockPrices
        .take(2) // 取最近两个价格
        .map { it.price }
        .runningReduce { old, new -> ((new - old) / old) * 100 } // 计算变化率
}

data class StockPrice(val symbol: String, val price: Double, val timestamp: Long)

9. 性能优化和最佳实践

9.1 性能优化技巧

kotlin 复制代码
suspend fun performanceTips() {
    val flow = (1..1000).asFlow()
    
    // 1. 合理使用 buffer
    flow
        .map { heavyOperation(it) }
        .buffer() // 允许map并发执行
        .collect { println(it) }
    
    // 2. 避免不必要的操作链
    flow
        .filter { it % 2 == 0 }
        .map { it * 2 } // 先过滤再映射,减少操作次数
        .collect()
    
    // 3. 使用 flowOn 合理分配上下文
    flow
        .map { cpuIntensiveOperation(it) }
        .flowOn(Dispatchers.Default) // CPU密集型在Default调度器
        .map { ioOperation(it) }
        .flowOn(Dispatchers.IO) // IO操作在IO调度器
        .collect()
}

suspend fun heavyOperation(value: Int): Int {
    delay(10)
    return value * 2
}

suspend fun cpuIntensiveOperation(value: Int): Int {
    // 模拟CPU密集型操作
    return value * value
}

suspend fun ioOperation(value: Int): String {
    delay(50) // 模拟IO操作
    return "结果: $value"
}

9.2 测试 Flow

kotlin 复制代码
@Test
fun `test flow operations`() = runTest { // 使用TestScope
    val flow = flowOf(1, 2, 3, 4, 5)
    
    val result = flow
        .filter { it % 2 == 0 }
        .map { it * 2 }
        .toList()
    
    assertEquals(listOf(4, 8), result)
}

// 测试超时和异常
@Test
fun `test flow timeout`() = runTest {
    val slowFlow = flow {
        emit(1)
        delay(1000) // 长时间延迟
        emit(2)
    }
    
    assertFailsWith<TimeoutCancellationException> {
        withTimeout(500) { // 设置超时
            slowFlow.collect()
        }
    }
}

10. Flow 与 Channel 的比较

特性 Flow Channel
数据模式 数据流(可能无限) 点对点通信
背压处理 自动处理 需要手动配置缓冲
冷热性 冷流(默认) 热流
使用场景 数据处理管道 协程间通信
多个消费者 每个消费者独立流 共享数据

通过全面掌握 Flow 的各种操作符和特性,你可以构建出高效、响应式的异步数据处理管道,充分发挥 Kotlin 协程在异步编程中的优势。

相关推荐
heeheeai3 小时前
kotlin图算法
算法·kotlin·图论
ZHANG13HAO3 小时前
Android 13 完整实现 USB 网卡支持与网络优先级配置(USB>WiFi>4G)
android·网络
梦终剧3 小时前
【Android之路】界面和状态交互
android·交互
孙小二3 小时前
Android主题切换
android
帅锅锅0074 小时前
Android.mk 编辑脚本
android
火柴就是我5 小时前
Android 记录View绘制坐标抖动问题
android
余衫马5 小时前
Ubuntu24.04 安卓模拟器安装指南
android·容器·模拟器
诺诺Okami5 小时前
Android Framework-WMS-动画-初步认识
android
用户2018792831675 小时前
Try-Catch-Finally中的Return执行顺序:一个外卖配送的故事
android