网站服务器做缓存吗,百度快速排名案例,营销思路,教育类网站建设方案Kotlin Flow 操作符
以下文章来源于RockByte #xff0c;作者RockByte.
十分钟速览 Kotlin Flow 操作符
一对一转换
map
将 Flow 中发出的每个元素转换为新元素#xff0c;实现一对一映射。
fun main() runBlocking {flowOf(Kotlin, Flow).ma…Kotlin Flow 操作符以下文章来源于RockByte 作者RockByte.十分钟速览 Kotlin Flow 操作符一对一转换map将Flow中发出的每个元素转换为新元素实现一对一映射。funmain()runBlocking{flowOf(Kotlin,Flow).map{Length of $it is${it.length}}.collect{println(it)}}// output:// Length of Kotlin is 6// Length of Flow is 4适用场景需要将每个项转换为不同类型或格式例如在ViewModel中将Date对象格式化为可显示的String。filter仅允许满足给定条件的元素通过。funmain()runBlocking{(1..5).asFlow().filter{it%20}.collect{println(it)}}// output:// 2// 4适用场景根据条件丢弃不需要的值例如过滤空搜索词或无效数据。take限制性操作符仅发出Flow的前n个元素随后取消Flow执行。funmain()runBlocking{(1..10).asFlow().take(3).collect{println(it)}}// output:// 1// 2// 3适用场景只需要有限数量的项例如分页加载或从一系列操作中取第一个有效结果。累积值reduce终端操作符从Flow的第一个元素开始累积值并对当前累加器与每个元素执行操作。若Flow为空则抛出异常。funmain()runBlocking{valsum(1..3).asFlow().reduce{accumulator,value-accumulatorvalue}println(sum)}// output:// 6fold类似于reduce但fold需要一个初始值是更安全的选择。即使Flow为空也会返回初始值。funmain()runBlocking{valsum(1..3).asFlow().fold(100){accumulator,value-accumulatorvalue}println(sum)}// output:// 106runningReduce / scan中间操作符在每个元素处理时都发出当前累积值。中间操作符不会触发Flow的收集所以需要collect触发Flow的收集而reduce这种终端操作符会触发Flow的收集。scan是更通用的版本支持指定初始种子值。funmain()runBlocking{println(runningReduce:)(1..3).asFlow().runningReduce{accumulator,value-accumulatorvalue}.collect{println(it)}println(scan:)(1..3).asFlow().scan(0){accumulator,value-accumulatorvalue}.collect{println(it)}}// output:// runningReduce:// 1// 3// 6// scan:// 0// 1// 3// 6注意他们会返回每一步的结果而reduce/fold只返回最终结果。适用场景计算累计总和、跟踪进度或在状态机中展示状态历史。发出多个值transform高度灵活的操作符可为每个输入元素发出零个、一个或多个值对输出流有更强控制力。funmain()runBlocking{(1..2).asFlow().transform{emit(Item:$it)if(it%2!0){emit(...is an odd number)}emit(Square:${it*it})}.collect{println(it)}}// output:// Item: 1// ...is an odd number// Square: 1// Item: 2// Square: 4适用场景执行复杂转换、引入副作用如日志记录或根据单个输入有条件地发出多个值。扁平化嵌套flatMapConcat将每个元素转换为一个Flow然后依次连接这些Flow只有当前一个Flow完成后下一个才开始。fungetNumbersFlow(id:Int):FlowStringflow{delay(100)emit(First-$id)delay(100)emit(Second-$id)}funmain()runBlocking{(1..2).asFlow().flatMapConcat{id-getNumbersFlow(id)}.collect{println(it)}}// output:// First-1// Second-1// First-2// Second-2仔细看第一个流的每个数字都会参与到第二个流中。适用场景顺序敏感的操作例如依次上传多个文件或执行依赖型网络请求。flatMapMerge并发合并由转换函数生成的多个Flow可通过concurrency参数控制并发数量。fungetNumbersFlow(id:Int):FlowStringflow{delay(100)emit(First-$id)delay(100)emit(Second-$id)}suspendfunmain(){(1..2).asFlow().flatMapMerge{id-getNumbersFlow(id)}.collect{println(it)}}// output:// First-1// First-2// Second-2// Second-1从结果上注意区分flatMapConcatflatMapMerge不会保证合并的顺序。适用场景顺序无关的并行操作例如同时从多个数据源获取数据。flatMapLatest当新元素发出时立即取消上一个元素对应的Flow。valsearchQueryflowOf(search,search with new term).onEach{delay(200)}funsearchApi(query:String):FlowStringflow{emit(Searching for $query...)delay(500)// 模拟网络延迟emit(Results for $query)}suspendfunmain(){searchQuery.flatMapLatest{query-searchApi(query)}.collect{println(it)}}// output:// Searching for search...// Searching for search with new term...// Results for search with new term适用场景实时搜索功能或任何只需关注最新事件结果的场景。上下文与缓冲flowOn更改用于执行上游Flow的CoroutineContext是Flow中切换调度器的正确方式。funheavyWork():FlowIntflow{println(Starting heavy work on${Thread.currentThread().name})for(i in1..3){// Simulate CPU-intensive workThread.sleep(100)emit(i)}}funmain()runBlocking{heavyWork().flowOn(Dispatchers.IO)// Upstream runs on IO dispatcher.collect{println(Collected$iton${Thread.currentThread().name})}// Downstream runs on the collectors context (e.g., Main)}// output:// Starting heavy work on DefaultDispatcher-worker-1// Collected 1 on main// Collected 2 on main// Collected 3 on mainbuffer通过解耦生产者与消费者实现并发执行生产者将项放入缓冲区消费者从中取出。suspendfunmain(){valtimemeasureTimeMillis{flow{for(i in1..3){delay(200)// Simulate slow emissionemit(i)}}.buffer()// With buffer, the total time is closer to the slow collectors time.collect{delay(300)// Simulate slow collectionprintln(it)}}println(Collected in$timems)}// output:// 1// 2// 3// Collected in 1172 ms得益于buffer最后整个数据的收集时间要小于(200 300) * 3。使用场景当生产者与消费者处理速度不一致时提升性能。conflate一种缓冲形式当收集器处理太慢时会丢弃中间值确保始终获取最新值。suspendfunmain(){flow{for(i in1..5){delay(100)emit(i)}}.conflate().collect{value-println(Started processing$value)delay(300)println(Finished processing$value)}}// output:// Started processing 1// Finished processing 1// Started processing 3// Finished processing 3// Started processing 5// Finished processing 5适用场景UI 更新中无需显示中间状态如股票行情或 GPS 位置更新。collectLatest终端操作符当新值发出时取消对前一个值的收集逻辑。suspendfunmain(){(1..3).asFlow().onEach{delay(100)}.collectLatest{value-println(Collecting$value)delay(300)println(Finished collecting$value)}}// output:// Collecting 1// Collecting 2// Collecting 3// Finished collecting 3注意看这里的结果Finished collecting 只收集了最后一次的值一定要注意这个特性。适用场景某项操作耗时较长且应在新项到达时被取消例如将用户输入保存到数据库。合并zip等待两个Flow各自发出一项后进行组合。任一源Flow结束结果Flow即结束。suspendfunmain(){valflowA(1..3).asFlow()valflowBflowOf(A,B,C,D)flowA.zip(flowB){number,letter-$number$letter}.collect{println(it)}}// output:// 1A// 2B// 3Ccombine组合两个Flow的最新值。只要任一源Flow发出新值且双方至少各发出过一次就会触发一次发射。suspendfunmain(){valflowA(1..3).asFlow().onEach{delay(100)}valflowBflowOf(A,B).onEach{delay(150)}flowA.combine(flowB){number,letter-$number$letter}.collect{println(it)}}// output:// 1A// 2A// 3A// 3B适用场景响应多个数据源的变化。merge将多个Flow合并为一个按发出顺序交错输出所有值。suspendfunmain(){valflowAflowOf(A1,A2).onEach{delay(100)}valflowBflowOf(B1,B2).onEach{delay(50)}merge(flowA,flowB).collect{println(it)}}// output:// B1// A1// B2// A2适用场景将来自不同 UI 组件的多个事件流合并为单一处理流。错误与完成处理catch捕获上游Flow即catch之前的操作符中发生的异常但不捕获下游收集器中的异常。suspendfunmain(){flow{emit(1)throwRuntimeException(Error!)}.catch{e-println(Caught:${e.message})emit(-1)// Emit a fallback value}.collect{println(it)}// Emits 1, then -1}// output:// 1// Caught: Error!// -1适用场景优雅地处理错误、提供默认值或记录失败信息。onCompletion在Flow完成时无论成功或异常执行指定操作。成功时cause为null。suspendfunmain(){(1..3).asFlow().onCompletion{cause-if(cause!null)println(Flow completed with error)elseprintln(Flow completed successfully)}.collect{println(it)}}// output:// 1// 2// 3// Flow completed successfullyretryWhen在发生异常时根据谓词包含异常原因和重试次数决定是否重试。suspendfunmain(){varattemptCount0flow{emit(1)if(attemptCount2){attemptCountthrowRuntimeException(Transient error)}emit(2)}.retryWhen{cause,attempt-println(Attempt$attempt: Retrying due to${cause.message})delay(100)// Add a delay before retryingattempt2// Retry up to 2 times}.catch{println(Caught final error:${it.message})}.collect{println(it)}}// output:// 1// Attempt 0: Retrying due to Transient error// 1// Attempt 1: Retrying due to Transient error// 1// 2retryWhen的回调有两个参数cause导致Flow失败的异常Throwable类型。attempt当前是第几次重试从0开始计数。工具与副作用onEach对Flow中每个元素执行指定操作但不修改元素本身。suspendfunmain(){(1..3).asFlow().onEach{println(About to process$it)}.map{it*it}.collect{println(Processed value:$it)}}// output:// About to process 1// Processed value: 1// About to process 2// Processed value: 4// About to process 3// Processed value: 9适用场景用于日志、调试或埋点等副作用场景在不改变数据的前提下观察Flow。debounce过滤在指定超时内被新值取代的值仅发出“突发”中的最后一个值。suspendfunmain(){flow{emit(1)delay(90)emit(2)delay(90)emit(3)delay(500)emit(4)delay(90)emit(5)}.debounce(100).collect{println(it)}}// output:// 3// 5适用场景处理快速用户输入如搜索框避免每次按键都触发 API 请求。distinctUntilChanged抑制与前一个值相同的重复发射。suspendfunmain(){flowOf(1,1,2,2,1,3).distinctUntilChanged().collect{println(it)}}// output:// 1// 2// 1// 3适用场景防止 UI 因状态未变而进行不必要的重组或更新。核心决策指南数据转换。用于修改流中的值mapfilterdistinctUntilChanged。累积值。用于跟踪状态或计算持续结果scanrunningReducefoldreduce。从单一输入发出多个值。用于自定义发射逻辑transform。处理嵌套或动态Flow。根据内部Flow行为选择flatMapConcat顺序执行、flatMapMerge并发执行、flatMapLatest取消旧任务保留最新。性能与背压控制。用于优化收集效率与响应性bufferconflatecollectLatestflowOn。合并多个流。用于组合多个数据源zip按顺序配对、combine组合最新值、merge交错合并。错误处理与完成逻辑。用于应对异常和生命周期事件catchonCompletionretryWhen。调试与副作用。用于插入日志或副作用操作onEach。处理高频发射。用于抑制过快的发射频率debounce。触发Flow执行。终端操作符collectcollectLatestfirstsingletoListreducefold。