当前位置: 首页 > news >正文

第一篇:为什么多个 Flow collect 必须 launch?——一篇讲透 Android 协程生命周期

引言很多 Android 开发在刚接触 Kotlin 协程 Flow 时都会写出类似代码lifecycleScope.launch { mViewModel.loadingFlow.collect { // 更新 loading } mViewModel.errorFlow.collect { // 处理错误 } }然后发现第二个 collect 根本不执行。很多人第一反应是不是协程有问题 是不是 Flow 有 bug实际上这恰恰说明你还没有真正理解collect 本质Flow 生命周期协程结构化并发lifecycleScoperepeatOnLifecycle今天这篇文章 我们就从工程视角真正讲透Android 中 Flow 为什么不能乱 collect。一、collect 本质到底是什么很多人误以为collect {}类似list.forEach {}执行完就结束。实际上collect 通常是长期挂起任务。例如mViewModel.loadingFlow.collect { isLoading - }本质是一直监听 loadingFlow只要数据变化就回调 collect也就是说collect 默认不会自动结束。它会一直挂起等待新数据。二、为什么第二个 collect 不执行来看错误示例lifecycleScope.launch { mViewModel.loadingFlow.collect { Log.d(TAG, loading) } mViewModel.errorFlow.collect { Log.d(TAG, error) } }问题就在这里loadingFlow.collect {}会一直挂起。所以后面的代码根本执行不到。即第一个 collect 永远不结束 ↓ 第二个 collect 永远没机会执行三、正确写法多个 collect 必须 launch正确写法lifecycleScope.launch { launch { mViewModel.loadingFlow.collect { Log.d(TAG, loading) } } launch { mViewModel.errorFlow.collect { Log.d(TAG, error) } } }为什么这样可以因为launch {}会创建子协程。结构变成父协程 ├── 子协程Acollect loading └── 子协程Bcollect error这样两个 collect 并发执行 互不阻塞四、lifecycleScope 到底是什么很多人觉得lifecycleScope.launch {}只是开个协程其实不是。lifecycleScope 本身就是 CoroutineScope。它内部已经绑定LifecycleJobMain Dispatcher所以lifecycleScope.launch {}本质是在 Activity 生命周期范围内 创建一个子协程五、lifecycleScope 到底解决了什么核心Activity 销毁时自动 cancel 协程。即Activity finish ↓ lifecycleScope cancel ↓ 所有子协程 cancel因此lifecycleScope.launch { }不用担心页面销毁后协程泄漏六、但 lifecycleScope 不解决一个问题很多人以为lifecycleScope.launch {}已经彻底解决生命周期问题。实际上不是。因为页面进入后台时 Activity 不一定销毁例如按 Home 键打开别的页面锁屏此时lifecycleScope 还活着 collect 还在继续这就会导致后台继续收集数据后台继续更新 UI后台继续弹 Toast后台继续执行逻辑显然不合理。七、repeatOnLifecycle 真正解决了什么正确写法lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { mViewModel.loadingFlow.collect { } } } }它的核心页面可见时开始 collect。页面不可见时停止 collect。即进入前台 ↓ 开始收集 进入后台 ↓ 停止收集 再次回到前台 ↓ 重新收集八、企业级推荐写法很多人会这样写lifecycleScope.launch { repeatOnLifecycle { collect A } } lifecycleScope.launch { repeatOnLifecycle { collect B } }其实不是错。完全能跑。但问题是生命周期入口过多 结构分散 维护困难九、真正推荐的结构化写法推荐private fun observeUiState() { lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { mViewModel.loadingFlow.collect { isLoading - } } launch { mViewModel.errorFlow.collect { error - } } launch { mViewModel.loginFlow.collect { user - } } } } }结构变成lifecycleScope └── ObserverRoot ├── loadingFlow ├── errorFlow └── loginFlow优势生命周期入口统一所有 UI 状态统一管理更符合结构化并发思想更适合大型项目维护十、协程真正核心结构化并发很多人觉得launch {}只是开线程实际上Kotlin 协程核心是Structured Concurrency结构化并发即所有协程都应该有父协程。因此launch {}本质是在当前 CoroutineScope 下 创建一个子协程节点所以lifecycleScope.launch { launch {} launch {} }本质结构lifecycleScope └── Parent ├── ChildA └── ChildB十一、Job 是什么val job launch { }返回Job本质协程控制器。可以job.cancel()取消协程。十二、为什么 collect 可以 cancel因为Flow collect 是可取消挂起函数。当job.cancel()时collect 收到取消信号 ↓ 停止监听 ↓ 协程结束十三、最后总结这一轮真正要理解的核心协程不是“开线程”。而是在协程树中 创建一个受生命周期与父 Job 管理的任务节点。而Flow collect本质是长期挂起监听任务。所以多个 collect 必须并发 launch。最终企业级推荐写法lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { mViewModel.loadingFlow.collect { } } launch { mViewModel.errorFlow.collect { } } launch { mViewModel.loginFlow.collect { } } } }下篇预告下一篇我们继续《StateFlow 与 SharedFlow 到底怎么选——一篇讲透 Android 热流设计》深入讲透StateFlow 为什么必须有初始值SharedFlow 为什么适合事件Toast 为什么不能用 StateFlow页面旋转为什么会重复消费replay 到底是什么emit 与 tryEmit 的真正区别热流与冷流本质区别企业级 UI 状态设计方案
http://www.zskr.cn/news/1408364.html

相关文章:

  • 基于FiGaRO架构的RISC-V原生真随机数生成器设计与集成
  • 小白/程序员必备:收藏!轻松学会使用大模型进行数据验证
  • 为内部知识库问答系统接入Taotoken提供多模型后备支持
  • ShuffleNet:从通道混洗到移动端部署的轻量化艺术
  • IDM激活终极指南:2025年完整教程与永久使用技巧
  • Windows Defender终极恢复指南:5种强力方法解决禁用问题
  • 拯救者 Y70 隐藏玩法!一键自定义充电样式,氛围感直接拉满
  • 逆向工程指点杆:从PTPM754DR引脚到自定义接口的实战解析
  • 中小型创业公司如何利用Taotoken构建高性价比的AI应用后端
  • 这次终于选对了!降AIGC工具测评:2026 最新好用推荐与对比分析
  • 2026年适配知网降AIGC网站横评:亲测8款工具,把AI率稳控在安全线内
  • 如何用Python命令行工具突破百度网盘下载限速:完整实战指南
  • AzurLaneAutoScript:碧蓝航线智能自动化脚本,彻底解放你的游戏时间
  • 【复现】并离网风光互补制氢合成氨系统容量-调度优化分析附Matlab代码
  • STM32F407驱动DHT22:从时序解析到稳定读取的嵌入式实践
  • LLVM IR指令精解:从基础运算到内存与类型转换
  • 临近毕业4款降AI软件实测:哪个真的去ai痕迹,哪个是智商税
  • 时序解耦自编码器:用 β‑VAE 和 TCN 实现铣削刀具磨损的可解释异常检测
  • novel-downloader:全网小说下载终极方案,一站式解决离线阅读难题
  • Kubernetes日志管理与分析:构建全面的日志体系
  • 从像素到地图:解析航摄比例尺、地面分辨率与成图精度的三角关系
  • C语言--day20
  • 仿生六足机器人分层网络控制:从CPG原理到工程实现
  • 组合导航 | 基于matlab的开源卫惯组合导航算法总结汇总
  • 实测DeepSeek V4 Pro接入CodeX,今后CodeX也可以使用Deepseek了。
  • 20260527 之所思 - 人生如梦
  • 从传感器配置到Rviz可视化:深入解析Xsens MTI-G-710在ROS中的坐标系与数据流(附display.launch详解)
  • 27考研408计算机历年真题PDF
  • 都在说油车不行,可是经销商倒闭、夸张的1亿订单都与电车有关!
  • 非对称双向DC/DC转换器主动功率均分控制:原理、模式与实现