清华大学有关网站建设的书12306网站建设投标书
2026/4/18 10:34:38 网站建设 项目流程
清华大学有关网站建设的书,12306网站建设投标书,wordpress建站双语,北京网站建设哪便宜1.什么是Flow 基于协程的异步数据流#xff08;cold stream#xff09;Flow在协程基础上构建的响应式流#xff0c;用于处理异步数据序列 2.Flow的作用 异步返回多个值#xff0c;不会阻塞线程 fun simpleFlow() flow {delay(1000)emit(1) }Test fun test()runBlockingcold streamFlow在协程基础上构建的响应式流用于处理异步数据序列2.Flow的作用异步返回多个值不会阻塞线程funsimpleFlow()flow{delay(1000)emit(1)}Testfuntest()runBlockingUnit{simpleFlow().collect{println(it)}}这段代码中simpleFlow函数无需标记为suspend是因为Flow 构建器flow { }内部是挂起 lambda可以用delay。也就是说flow中的代码在你使用simpleFlow()时还不会执行这里只是拿到了一个Flow对象只有你使用simpleFlow().collect{println(it)}时才会执行flow{}里面的delay和emit这就是为什么叫做冷流flow要注意的是 collect 的函数必须是suspend函数或者运行在协程中launch / async / runBlocking。3.流的连续性对于流中的元素是按顺序去处理直至当前元素处理完成再去处理下一个元素Testfuntest flow continuation()runBlocking{(1..5).asFlow()//这里的.asFlow()将集合转换为 Flow冷流相当于创建了一个会发射 1, 2, 3, 4, 5 这5个值的流.filter{println(Filter$it)it%20}.map{println(Map$it)string$it}.collect{println(Collect$it)}}执行流程分析注意不是先过滤所有数字再映射所有结果最后收集而是每个数据走一遍全流程执行流程 Filter 1 Filter 2 Map 2 Collect string 2 Filter 3 Filter 4 Map 4 Collect string 4 Filter 54.背压Backpressure生产者的效率大于消费者的效率Flow 自动处理背压下游处理得慢上游就会等待也就是生产者会等消费者消费完成之后再继续生产(1..5).asFlow().onEach{delay(100)}// 生产慢.collect{delay(500)// 消费更慢println(it)}// 不会丢失数据只是整体变慢防抖Debounce在事件被触发后等待一段时间比如300ms如果在这段时间内事件没有再被触发才执行处理函数。如果在这段时间内事件再次被触发则重新计时。用户输入防抖处理searchInput.changes()// 输入变化流.debounce(300)// 防抖 300ms.filter{it.length3}// 至少3个字符.distinctUntilChanged()// 去重.flatMapLatest{query-// 最新搜索repository.search(query)}.collect{results-updateUI(results)}处理背压的性能优化4.1 设置缓冲使用buffer( )设置缓冲区通过背压管理优化性能单线程异步并发//在缓冲区还有空的情况下生产者可以提前生产元素存入缓冲区消费者按需从缓冲区取出funsimpleFlow8()flowInt{for(iin1..3){delay(100)emit(i)println(Emitting$i${Thread.currentThread().name})}}Testfuntest flow back pressure()runBlockingUnit{valtimemeasureTimeMillis{simpleFlow8().buffer(capacity150)//设置缓冲区可以存放150个元素.collect{value-delay(300)// 处理这个元素消耗300msprintln(Collected$value${Thread.currentThread().name})}}println(Collected in$timems)}时间(ms)| 生产者线程 | 缓冲区 | 消费者线程0-100| 生产1→ 缓冲区 |[1]|100-200| 生产2→ 缓冲区 |[1,2]| 开始消费1(0-300)200-300| 生产3→ 缓冲区 |[1,2,3]| 继续消费1300-400| 生产者完成 |[2,3]| 开始消费2(300-600)400-600| 空闲 |[3]| 继续消费2600-900| 空闲 |[]| 消费3(600-900)4.2 线程分离使用flowOn( )指定上游操作的执行线程如使用flow{}构建器则是指定flow{ }中代码的执行线程只要和collect不是同一个线程就可以达到多线程并行的效果。假如不使用flowOn( ),那么生产者和消费者就在同一线程中串行执行也就是emit不会立刻返回而是在消费者完成消费之前会挂起这也决定了生产者会等消费者消费完成之后再继续生产4.3 合并处理conflateflow{emit(A)// 消费者开始处理A需要300msdelay(100)emit(B)// 替换缓冲区但消费者在处理Adelay(100)emit(C)// 替换Bdelay(100)emit(D)// 替换C// 消费者还在处理A...}.conflate().collect{value-//从这里开始缓冲区的元素就被消费者取走了delay(300)// 处理需要300msprintln(处理:$value)}实际可能发生 text 时间线 0ms:emit(A)→ 消费者开始处理A 100ms:emit(B)→ 缓冲区[B]A已被取走 200ms:emit(C)→ 缓冲区[C]替换B 300ms:emit(D)→ 缓冲区[D]替换C 300ms:消费者完成处理A取缓冲区最新值 → 得到D 开始处理Dconflate()确保的是缓冲区永远不会堆积最多1个等待值生产者永远不会被阻塞可以一直生产消费者总是得到它取数据时缓冲区的最新值不会处理太旧的中间值会跳过一些4.4 获取最新元素collectLatest{ }.collectLatest{value-// 取消旧的处理新的// 如果新值来了会取消当前处理那也得当前还没执行结束// 确保总是处理最新开始的}5.流的构建器 flow函数flowOfasFlowflow函数可以进行比较复杂的逻辑从外部获取数据错误处理等funmain()runBlocking{// 创建FlowvalmyFlowflow{// 在流构建器中手动发射值emit(1)delay(100)// 可以挂起emit(2)emit(3)}// 收集流myFlow.collect{value-println(收到:$value)}}// 输出// 收到: 1// (等待100ms)// 收到: 2// 收到: 3flowOf():创建固定值流其中不能包含挂起操作如delay()内部也是emit了funmain()runBlocking{// 创建包含固定值的流valfixedFlowflowOf(1,2,3,4,5)fixedFlow.collect{value-println(值:$value)}// 输出: 值: 1, 值: 2, 值: 3, 值: 4, 值: 5// 也可以包含不同类型的值valmixedFlowflowOf(苹果,3,true,9.99)mixedFlow.collect{println(it)}// 输出: 苹果, 3, true, 9.99.asFlow():集合转Flow适合已有集合的情况下默认内部已经emit了funmain()runBlocking{// 1. List 转 FlowvallistFlowlistOf(1,2,3,4,5).asFlow()listFlow.collect{println(列表项:$it)}// 2. Array 转 FlowvalarrayFlowarrayOf(A,B,C).asFlow()// 3. Range 转 FlowvalrangeFlow(1..5).asFlow()// 4. Sequence 转 FlowvalsequenceFlowgenerateSequence(1){it*2}.take(5).asFlow()// 5. Map 转 Flow发射EntryvalmapFlowmapOf(ato1,bto2).asFlow()mapFlow.collect{(key,value)-println($key-$value)}}流的收集和流的构建在同一个协程的上下文流的该属性称为上下文保存6.指定流发射或收集的线程flow{}构建器必须遵循上下文保存的特性并且不允许从其他上下文emit发射但是可以通过.flowOn(Dispatchers.Default)修改流发射的上下文消费者决定生产者起点所在的线程但是假如生产者中进行了retrofit网络请求那么会切换到后台线程okHttp线程池进行网络请求网络请求完成协程恢复执行时是在OkHttp线程中导致collect也在OkHttp线程中执行.launchIn(),指定流收集的线程events().onEach{event-println(Event:$event$(Thread.currentThread().name))}.launchIn(CoroutineScope(Dispatchers.IO))//隐式调用了collect.join()7.流的取消7.1 cancel()在collect{}中执行流的取消注意不能在Flow构建器中去执行取消一般情况下流构建器中如果存在挂起点则会对每个发射的值执行附加的ensureActive检测检测收集流所在协程的active下文中的执行cancel实际上是异步把当前协程的JobJob协程的控制器用来管理协程生命周期设置为CANCELLING最终变为CANCELLEDensureActive( )返回false不再收集数据funtestCannel()runBlocking{valfflow{for(iin1..5){emit(i)}}f.collect{value-println(value)if(value3){cancel()//// 或coroutineContext.cancel()}}}但是当流的发射没有挂起点如使用asFlow和flowOf构建的流cancel( )确实会把Job的状态变为CANCELLED但是由于 Kotlin 的同步优化emit()可能不真正挂起而是直接调用下游。当它不挂起时虽然检查了状态但检查时机不同导致取消的响应性不同。但是Flow 有一个同步优化如果生产者和消费者在同一调用栈中且消费者处理速度很快同一个调用栈意味着✅函数调用连续emit()直接调用collectlambda✅无挂起恢复不经过协程的挂起/恢复机制✅调用栈ID相同可以用堆栈跟踪验证⚠️可能在同一线程但同一线程不一定保证同一调用栈简单判断方法如果 Flow 中没有delay()、withContext等挂起函数且没有使用flowOn、buffer等操作符那么很可能被优化为同一个调用栈执行7.2 cancellable( ):强制每次发射检查状态funtestCannel()runBlocking{valjoblaunch{flowOf(1,2,3,4,5,6,7,8,9,10).cancellable().collect{value-println(value)if(value5){println(调用 cancel() 前 Job 状态:${coroutineContext[Job]?.isActive})cancel()println(调用 cancel() 后 Job 状态:${coroutineContext[Job]?.isActive})}}}}输出12345调用cancel()前 Job 状态:true调用cancel()后 Job 状态:false//假如没有cancellable还会继续输出6到108.操作符8.1 转换操作符maptransform//transform可以一变多(1..3).asFlow().transform{emit(transformA:$it)emit(transformB:$it)}.collect{println(it)}8.2 限长操作符take8.3末端操作符collect是最基础的末端操作符valnumberslistOf(1,2,3,4,5)// reduce从第一个元素开始累积valsumnumbers.reduce{acc,num-accnum}// 15valproductnumbers.reduce{acc,num-acc*num}// 120// fold指定初始值valsumFrom10numbers.fold(10){acc,num-accnum}// 25 (1012345)valconcatenatednumbers.fold(){acc,num-$acc$num}// 123458.4 组合操作符用于将两条流进行组合输出.zip下列两流是异步的也就是总的组合时间是400ms在这里插入图片描述8.5展平操作符1.flatMapConcat- 顺序连接模式特点顺序执行一个完成再下一个flow{emit(1)emit(2)emit(3)}.flatMapConcat{value-flow{emit(A$value)delay(100)emit(B$value)}}.collect{println(it)}输出A1 B1 ← 等1的Flow完成 A2 ← 才开始2 B2 A3 B32.flatMapMerge- 并发合并模式并发处理多个任务的能力逻辑概念可以通过单线程实现任务切换如某个协程作用域内出现delay(),会先挂起执行其他任务也可以通过多线程实现真正并行所以并行一定属于并发而并发不一定是并行特点并发执行第二个flow在耗时时切换回第一个flowfuntestFlatMapMerge()runBlocking{flow{emit(1)delay(100)// 延迟发射2emit(2)delay(100)// 延迟发射3emit(3)delay(100)// 延迟发射4}.flatMapMerge{value-// .flatMapMerge(2)并发数限制最大并发数也就是还未被消费的产品数上限flow{emit(开始$value)delay(200)emit(完成$value)}}.collect{println(${System.currentTimeMillis()}:$it)}}输出1766152720862: 开始1 1766152720973: 开始2 1766152721067: 完成1 1766152721081: 开始3 1766152721175: 完成2 1766152721285: 完成33.flatMapLatest- 最新优先模式特点当新值到达时立即取消前一个正在执行的内部 Flow只执行最新的。假如新值到达之前已经执行结束则无法被取消了funtestFlatMapMerge()runBlocking{flow{emit(1)delay(100)// 延迟发射2emit(2)delay(100)// 延迟发射3emit(3)delay(100)// 延迟发射4}.flatMapLatest{value-// 并发数限制flow{emit(开始$value)delay(200)emit(完成$value)}}.collect{println(${System.currentTimeMillis()}:$it)}}输出1766153200347: 开始1 1766153200480: 开始2 1766153200584: 开始3 1766153200786: 完成39.流的异常处理// 命令式 (try-catch) 详细指导厨师厨师请这样做1.先煎牛排每面3分钟2.如果煎糊了异常情况就换一块重新煎3.然后加盐和胡椒4.如果盐加多了就加点水稀释5.最后装盘// 声明式 (.catch) 描述你想要什么我想要一份-完美的牛排7分熟-如果做不到7分熟那就5分熟也可以-配黑胡椒酱-如果没有黑胡椒酱蘑菇酱也行在collect中使用check( )函数也可以根据其中的条件抛出异常9.1 try-catch块命令式用在collect时抛异常在collect外部try-catchfuntestCollectTryCatch()runBlocking{valflowflow{emit(1)emit(2)emit(3)//第三个数不会被发送}try{flow.collect{value-println(收集到:$value)if(value2){throwRuntimeException(收集时出错)}}}catch(e:Exception){println(在collect外部捕获异常:${e.message})}}输出收集到: 1 收集到: 2 在collect外部捕获异常: 收集时出错在collect内部try-catchfuntestCollectInnerTryCatch()runBlocking{flow{emit(1)emit(2)emit(3)}.collect{value-try{println(处理值:$value)if(value2){throwRuntimeException(处理值2时出错)}}catch(e:Exception){println(在collect内部捕获:${e.message})// 这里只能处理当前值的异常不能阻止Flow继续}}输出处理值:1处理值:2在collect内部捕获:处理值2时出错 处理值:3//还是会被发送9.2 .catch{}函数声明式一般当流构建器内抛异常的时候如funtestCatchException()runBlocking{flow{println(尝试执行)throwIOException(网络错误)emit(1)}.catch{e-println(异常:${e.message})delay(1000)// 延迟重试emit(2)}.collect{println(it)}}输出尝试执行 异常:网络错误//流构建器中异常之后的emit不再执行210.流的完成怎么知道流已经执行完成10.1 finally块(命令式)try{flow{emit(1)emit(2)emit(3)}.collect{value-println(处理值:$value)}}finally{println(Done)//无论流是否正常结束都会执行不知道流到底有没有抛异常}10.2 onCompletion(声明式).onCompletion{}在执行完毕时还可以拿到上游或者下游的异常消息但不是捕获捕获还得用catchfuntestOnCompletionBehavior():FlowIntflow{emit(1)emit(2)throwRuntimeException(模拟异常!)emit(3)// 永远不会执行}.onCompletion{cause:Throwable?-// 无论流如何结束这里都会执行println(onCompletion执行了! 原因:${cause?.message})}.collect{println(${it})}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询