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

协程与 Android 生命周期:该何时取消、何时保留

文章目录

  • 第 1 章 生命周期为什么约束协程
  • 第 2 章 lifecycleScope:短 UI 副作用
      • 踩坑
  • 第 3 章 viewModelScope 与 Fragment 取 VM
      • 踩坑
  • 第 4 章 repeatOnLifecycle:后台停止收集
      • 踩坑
  • 第 5 章 取消链:从 UI 到 Repository
  • 第 6 章 SupervisorJob 与并行任务
  • 动手练
        • 练习 1:Scope 选型(A · 基础)
        • 练习 2:viewLifecycleOwner(B · 进阶)
        • 练习 3:repeatOnLifecycle(D · Android 实践)
        • 练习 4:旋转行为(C · 综合)
        • 练习 5:反模式(B · 进阶)
        • 练习 6:WhileSubscribed(A · 基础)
  • 进阶阅读(可选)
      • 追问链 #1:lifecycleScope vs viewModelScope? 🔥
      • 追问链 #2:Fragment 旋转 collect 会断吗? 🔥
      • 追问链 #3:为何弃用 launchWhenStarted? ⭐
      • 追问链 #4:CancellationException 要 catch 吗? 💡
  • 完整链路一句通
  • 相关推荐

第 1 章 生命周期为什么约束协程

Activity/Fragment 会创建、显示、隐藏、销毁。协程若比界面活得更久,可能:

  1. 更新已销毁的 View → 崩溃或泄漏
  2. 后台白白耗电 collect 热流
  3. 旋转屏重复发请求 → 列表闪白

原则:能放 ViewModel 的异步逻辑不要只塞在lifecycleScope;UI Scope 负责「收集状态 + 短 UI 副作用」。

Scope绑定对象取消时机
lifecycleScopeLifecycleOwneronDestroy
viewModelScopeViewModelonCleared()
viewLifecycleOwner.lifecycleScopeFragment 的 View 生命周期onDestroyView

第 2 章 lifecycleScope:短 UI 副作用

classScanActivity:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)lifecycleScope.launch{delay(300)showHintSnackbar()// 短 UI 反馈}}}

权限结果、动画结束后再刷 Snackbar 等与界面同寿命的操作适合lifecycleScope

数据加载应进 ViewModel:

classTodoViewModel(privatevalrepo:TodoRepository,):androidx.lifecycle.ViewModel(){funload(){viewModelScope.launch{valitems=repo.loadAll()// _state.update { it.copy(items = items) } // 见《Flow 与 StateFlow》}}}

旋转屏销毁 Activity 但ViewModel 保留viewModelScope内请求可继续——这是 MVVM 里「数据不因旋转而重拉」的基础。

踩坑

  • lifecycleScope里调 Repository 拉列表——旋转可能取消请求或重复发起。

第 3 章 viewModelScope 与 Fragment 取 VM

classTodoListFragment:Fragment(){privatevalviewModel:TodoViewModelbyviewModels()overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super.onViewCreated(view,savedInstanceState)observeState()}privatefunobserveState(){viewLifecycleOwner.lifecycleScope.launch{viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED){viewModel.state.collect{ui->// 绑定列表}}}}}
  • by viewModels()保证旋转后仍是同一TodoViewModel
  • viewLifecycleOwner:Fragment 的 View 可能比 Fragment 实例先死,收集必须绑 View 生命周期。

踩坑

  • lifecycleScope(Fragment 实例)collect,在onDestroyView之后仍可能运行。

第 4 章 repeatOnLifecycle:后台停止收集

StateFlow是热流,ViewModel 一直在 emit。若在lifecycleScope.launch { flow.collect }直接 collect,App 进后台(onStop)后协程仍活着,白白耗电,还可能碰已销毁 View。

viewLifecycleOwner.lifecycleScope.launch{viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED){viewModel.state.collect{state->render(state)}}}

进入STOPPED时 cancel collect 块;回到STARTED重新 collect,并立刻拿到StateFlow当前值。

ComposecollectAsStateWithLifecycle()封装同样语义。

踩坑

  • 已废弃的launchWhenStarted:新代码用repeatOnLifecycle

第 5 章 取消链:从 UI 到 Repository

用户返回 / finish() → Activity onDestroy → lifecycleScope 取消 ViewModelStore 清空 → ViewModel.onCleared() → viewModelScope 取消 → 子协程收到 CancellationException repeatOnLifecycle 离开 STARTED → collect 协程取消(上游 stateIn 可按 WhileSubscribed 停)

suspend函数应在取消时尽快结束;阻塞 IO 要可中断;invokeOnCancellation解绑回调(《suspend 与 Continuation》)。


第 6 章 SupervisorJob 与并行任务

ViewModel 内并行多个独立launch时,viewModelScopeSupervisorJob使一个失败不取消兄弟——但仍应在子协程内runCatching转错误态:

viewModelScope.launch{launch{loadHeader()}launch{loadFooter()}}

不要在已取消的 scope 里更新 UI;检查isActive或在runCatching里忽略CancellationException


动手练

练习 1:Scope 选型(A · 基础)

目标:lifecycle vs viewModel。

要求:列表数据加载用哪个 Scope?Snackbar 延迟显示用哪个?各一句。

练习 2:viewLifecycleOwner(B · 进阶)

目标:Fragment 收集。

要求:Fragment collect Flow 为何用viewLifecycleOwner而不是this(Fragment)?

练习 3:repeatOnLifecycle(D · Android 实践)

目标:后台省电。

要求:说明不用repeatOnLifecycle时,App 进后台 collect 仍运行的问题。

练习 4:旋转行为(C · 综合)

目标:配置变更。

要求:旋转屏时lifecycleScopeviewModelScope各自怎样?正在进行的load()会不会中断?

练习 5:反模式(B · 进阶)

目标:识别坏写法。

要求lifecycleScope.launch { repo.loadAll(); adapter.submit(list) }有两处问题,各写一句。

练习 6:WhileSubscribed(A · 基础)

目标:与生命周期配合。

要求stateIn(WhileSubscribed(5000))在无 UI 订阅 5 秒后做什么?有什么好处?


进阶阅读(可选)

追问链 #1:lifecycleScope vs viewModelScope? 🔥

参考回答:前者绑界面,销毁即取消,适合短 UI;后者绑 ViewModel,跨配置变更,适合业务与 StateFlow 生产。

追问链 #2:Fragment 旋转 collect 会断吗? 🔥

参考回答repeatOnLifecycle在 STOPPED 取消 collect,STARTED 重启;ViewModel 与 state 保留,不中断业务协程。

追问链 #3:为何弃用 launchWhenStarted? ⭐

参考回答:暂停而非取消时行为易错;repeatOnLifecycle语义清晰,与 Flow 配合更好。

追问链 #4:CancellationException 要 catch 吗? 💡

参考回答:一般向上抛,不要当业务错误吞掉;runCatching要注意重新抛出取消。


完整链路一句通

业务进 viewModelScope 生产 StateFlowFragment by viewModels() 拿同一 VMviewLifecycleOwner.repeatOnLifecycle(STARTED) 内 collect后台自动停 collect销毁时 onCleared / CancellationException 收尾


相关推荐

  • Kotlin 作用域函数:let/apply 怎么选

  • Kotlin 语法与空安全:从零的第一课

http://www.jsqmd.com/news/1250624/

相关文章:

  • 思维导图AI化最后一公里难题:如何让AI理解“隐性逻辑关系”?神经符号系统实战解析(独家专利方法论)
  • 2026年申报书撰写类写作工具挑选攻略 青泥AI Flow等平台实测梳理 - 浩了个浩
  • P5481 [BJOI2015] 糖果 分析
  • 栈在递归中的应用
  • 纯网页免安装 TOP13 MBTI 测评入口,点开链接即可开启人格自测 - 时讯资讯
  • 南昌明档厨房火锅店推荐|同城多场景聚餐火锅门店盘点 - 品牌2026推荐
  • 20K芯片在天然产物靶点筛选中的应用价值
  • 2026年扭矩传感器品牌排行榜正式发布,广东犸力口碑爆棚,强势入选十大推荐排名 - 品牌速递
  • LoRA 适配器家族 — 从原版到新秀
  • 2026东莞广告标牌UV打印机/小型UV打印机怎么选?源头厂家选购避坑指南 - mobible
  • 2026最新指标测评|企业引入AI数字员工,团队如何筛选适配的服务商?
  • 2026年7月最新浪琴南昌恒隆广场维修保养服务电话 - 浪琴官方售后服务中心
  • 被低估的AI自动化临界点(单点突破→全链路提效的4.7天拐点实测数据)
  • 南昌脆毛肚火锅推荐|同城多场景聚餐门店觅食指南 - 品牌2026推荐
  • 数据结构篇(六):线性表——队列
  • 2026 年至今,彰武正规的蛙人打捞施工厂家哪家好,揭秘:水中“蛙人”打捞的惊人真相 - 企业信息推荐【官方】
  • AI工艺自动调整项目实现第1讲:整个工艺流程;方阻相关的问题;原数据理解;项目总思路;首先要完成的项目1
  • 测力传感器10大品牌推荐,广东犸力测力传感器值得信赖,研发人员推荐之选 - 品牌速递
  • 2026简历制作网站推荐:四款在线简历制作工具模板、AI功能与收费对比 - 春日收信人
  • 2026年绘资质延续人员社保要求
  • Spring Boot 接口幂等实战:用 Token + Redis 防重复提交
  • Micrometer 系列【1】JVM 可观测门面框架全景概述
  • 江诗丹顿中国售后服务中心|电话及维修地址权威信息公告(2026年7月最新) - 江诗丹顿服务中心
  • 2026年7月专业的室内墙面装修材料厂商推荐,旧墙翻新艺术涂料/微水泥艺术涂料,室内墙面装修材料厂商口碑推荐 - 品牌推荐师
  • 20260722 4(+1) 85 18
  • 保姆级教程:MCP 工具链搭建实战——从零配置 AI 编程助手
  • 南昌觅食指南:食材新鲜的重庆火锅门店场景盘点 - 品牌2026推荐
  • Pulsar 消息同步机制
  • 矿山破碎设备液压监测采购,液压传感器十大厂家推荐,广东犸力靠谱使用寿命更长 - 品牌速递
  • APS 需求计划(Demand Planning)技术拆解