【Jetpack Compose进阶学与练】第11课:ViewModel保存状态
目录一、前言二、知识点清单三、完整示例源码四、逐行解读五、容易踩坑六、多元化习题练习七、本节课知识点总结八、下一课预告—一、前言手机屏幕旋转、系统夜间模式切换会重新创建 Activity。普通的remember { mutableStateOf() }会丢失页面状态ViewModel 可以 survive存活页面重建但进程被系统memory killer后台杀掉之后ViewModel 会全部丢失。SavedStateHandle就是用来解决页面重建以及后台进程重启之后恢复状态的问题。本节课区分remember、ViewModel 内部变量、SavedStateHandle三者的区别演示SavedStateHandle的基础用法。前置依赖navigation-compose已经内置SavedStateHandle不需要额外的依赖。二、知识点清单1. Activity 重建之后各个状态的存活情况remember、ViewModel 成员变量、SavedStateHandleSavedStateHandle 是什么底层基于 BundleViewModel 接收 SavedStateHandle 构造参数读写简单值配合 Flow把 SavedStateHandle 的数据转为 StateFlow和 Navigation-Compose 结合Navigation 的返回页面重建场景## 三、完整示例源码importandroidx.lifecycle.SavedStateHandleimportandroidx.lifecycle.ViewModelimportandroidx.lifecycle.viewModelScopeimportandroidx.compose.runtime.Composableimportandroidx.compose.runtime.collectAsStateWithLifecycleimportandroidx.compose.runtime.getValueimportandroidx.compose.foundation.layout.Arrangementimportandroidx.compose.foundation.layout.Columnimportandroidx.compose.foundation.layout.fillMaxSizeimportandroidx.compose.material3.Buttonimportandroidx.compose.material3.Textimportkotlinx.coroutines.flow.StateFlowimportkotlinx.coroutines.flow.MutableStateFlowclassCounterViewModel(privatevalsavedStateHandle:SavedStateHandle):ViewModel(){privatevalKEY_COUNTkey_counter//先尝试从SavedStateHandle读取取不到默认0privateval_counterFlowMutableStateFlow(savedStateHandle[KEY_COUNT]?:0)valcounterFlow:StateFlowInt_counterFlowfunincrease(){valnewValue_counterFlow.value1_counterFlow.valuenewValue//同步写入SavedStateHandle保存到BundlesavedStateHandle[KEY_COUNT]newValue}}ComposablefunCounterSavedStateScreen(vm:CounterViewModel){valcountbyvm.counterFlow.collectAsStateWithLifecycle()Column(modifierandroidx.compose.ui.Modifier.fillMaxSize(),verticalArrangementArrangement.Center,horizontalAlignmentandroidx.compose.ui.Alignment.CenterHorizontally){Text(text计数$count)Button(onClick{vm.increase()}){Text(1)}}}四、逐行解读1. 页面重建屏幕旋转时三种状态存活对比remember { mutableStateOf() }Activity 重建直接丢失页面销毁就没了只存活当前 Composable 树生命周期。ViewModel 普通成员变量屏幕旋转 Activity 重建 ViewModel 还保留但是 App 后台被系统杀掉进程之后进程重启ViewModel 实例彻底消失数据全部清空。SavedStateHandle底层把数据保存进 Bundle屏幕旋转重建可以恢复后台系统杀进程重启 App 之后依然可以恢复保存的值。值。⚠️ SavedStateHandle只适合保存少量简单基础数据(Int、String、Boolean)不要放大对象、列表不适合存Bitmap。大量业务数据优先Room数据库持久化。SavedStateHandle如何注入ViewModel的构造增加参数 SavedStateHandle 使用ViewModelProvider或者Navigation‑Compose自动注入不要手动new SavedStateHandle()。读写SavedStateHandlesavedStateHandle[key]value//写valvsavedStateHandle[key]//读它内部使用键值对保存数据同时可以拿到Flow观察某个key的数据变化 savedStateHandle.getFlow(KEY_COUNT) 。和Flow配合业务里面ViewModel内部一般还是继续使用StateFlow驱动UI修改值之后同步把最新值写入SavedStateHandle做备份。进程重启之后ViewModel构造的时候优先从SavedStateHandle恢复初始值再给到StateFlow。Navigation Compose场景Navigation导航框架在创建页面ViewModel的时候会自动为每一个回退栈条目提供独立的SavedStateHandle每一个页面回退栈记录拥有自己的保存状态返回页面的时候可以恢复该页的状态。五、容易踩坑❌ 使用SavedStateHandle保存大型List、BitmapBundle有容量限制大数据请用Room。❌ 误以为SavedStateHandle可以永久保存卸载App、清除缓存数据依然丢失它属于实例状态保存不是持久化数据库。❌ 手动实例化new SavedStateHandle必须框架自动注入。✅ remember仅Compose组件生命周期ViewModel普通字段抗屏幕旋转怕进程被杀SavedStateHandle抗页面重建 进程后台被杀重启恢复仅少量简单数据。多元化习题练习习题1【基础‑改错题】直接在ViewModel里面保存一个很大的List业务列表依靠ViewModel抗屏幕旋转后台系统杀掉App进程重启之后列表直接消失如何改进答案SavedStateHandle不适合存放大型集合不能解决大量业务列表应当写入Room本地数据库App进程重启之后从数据库读取恢复SavedStateHandle只适合少量简单状态。解读Bundle存在大小上限禁止存放大量业务数据。习题2【基础‑代码修改题】页面保存用户输入的搜索关键词字符串key“search_keyword”写出向savedStateHandle写入该字符串的代码。答案savedStateHandle[search_keyword]inputText解读简单键值赋值支持StringIntBoolean等Bundle兼容基础类型。习题3【进阶‑补充代码题】savedStateHandle提供getFlow(key)可以直接拿到Flow请写出观察search_keyword的flow。答案valsearchKeywordFlowsavedStateHandle.getFlowString(search_keyword)解读当savedStateHandle当中对应key的值更新该flow就会发射新值可以直接收集。习题4【综合‑逻辑应用题】简述remember、ViewModel普通成员变量、SavedStateHandle三者生命周期差异。答案remember跟随Compose组件树页面重组没事Activity重建旋转屏幕直接丢失ViewModel普通成员变量Activity重建还存活App后台被系统杀掉进程重启之后数据丢失SavedStateHandle数据写入Bundle屏幕旋转重建恢复后台进程被杀重启之后也可以恢复仅适合少量简单状态。解读根据数据的重要程度选择合适保存方案重要业务数据走Room。习题5【概念简答题】SavedStateHandle底层存储介质是什么答案底层基于Android系统BundleBundle是Android系统用于页面保存实例状态的容器。解读Bundle由操作系统负责保存所以进程被杀之后依然能够取回。本节课知识点总结remember状态Activity重建就丢失ViewModel普通成员变量抗屏幕旋转进程被杀之后丢失SavedStateHandle基于Bundle抗屏幕旋转后台进程重启恢复少量状态。ViewModel构造接收SavedStateHandle由框架自动注入不要手动new。SavedStateHandle适合Int、String、Boolean少量简单状态禁止存放大数据集合与图片大量业务数据使用Room。可以配合getFlow拿到数据流项目经常做法StateFlow驱动UI变更同时同步写入SavedStateHandle备份。Navigation‑Compose当中每一条回退栈条目拥有独立SavedStateHandle各个页面状态互不干扰。下一课预告进阶第12课Compose项目完整目录结构模块化单Activity架构

相关新闻

r-nacos内置MCP Server,存量HTTP接口零改造接入AI Agent

r-nacos内置MCP Server,存量HTTP接口零改造接入AI Agent

最近MCP协议在技术圈的热度快被聊烂了:同花顺在做行情数据的MCP接入,Playwright在做浏览器自动化的MCP控制,好几家中后台框架也在原生支持MCP。可这些例子落到我们自己业务系统上,就有点尴尬了——公司有几十个注册在Nacos上的普通…

2026/10/13 9:00:51 阅读更多 →
能量回馈式变流器负载试验装置:方案选型与调试实践

能量回馈式变流器负载试验装置:方案选型与调试实践

1. 方案定位:先搞清楚到底要测什么、省多少电干电力电子这一行的人,对“负载试验”这四个字应该都不陌生。一台变流器出厂前,不做满功率带载测试根本不敢交付——器件的热稳定性、控制参数是否收敛、保护逻辑是否可靠,这些问题只通…

2026/10/12 0:54:46 阅读更多 →
入职第一天看不懂祖传代码?5 分钟速成 GitDiagram 读码法

入职第一天看不懂祖传代码?5 分钟速成 GitDiagram 读码法

入职第一天看不懂祖传代码?5 分钟速成 GitDiagram 读码法 【免费下载链接】gitdiagram Visualize any GitHub codebase: free interactive architecture diagrams and one-minute explainer videos. Replace hub with diagram in any GitHub URL. 项目地址: https…

2026/10/12 0:54:50 阅读更多 →

最新新闻

矩阵论期末复习:Jordan标准形、QR分解与广义逆手算全攻略

矩阵论期末复习:Jordan标准形、QR分解与广义逆手算全攻略

简介:矩阵论期末考试参考答案是一份针对矩阵论课程期末考试的完整解题资料,面向正在复习矩阵论、线性代数的本科生及考研备考生,也适用于需要快速回顾核心计算方法的工程类学生。资源包内共1个PDF文件,大小约284KB,文件…

2026/10/13 19:15:31 阅读更多 →
OSPF协议细节深度解析:LSA类型、邻居状态机与SPF算法

OSPF协议细节深度解析:LSA类型、邻居状态机与SPF算法

1. 为什么OSPF不是“配通就行”,而是网络工程师的分水岭 在某高校网络实验室带学生做路由实验时,我见过太多次这样的场景:A同学花15分钟把OSPF邻居关系配通, show ip ospf neighbor 显示FULL,ping测试全通&#xff0…

2026/10/13 19:15:30 阅读更多 →
夸克网盘免费扩容1TB全攻略:从活动入口到空间验证一步不落

夸克网盘免费扩容1TB全攻略:从活动入口到空间验证一步不落

夸克网盘免费扩容1TB这个话题,隔一阵子就会有人翻出来问一遍。网上教程截图满天飞,但真正把入口在哪、任务怎么算完成、到账怎么验证、有效期怎么查讲清楚的并不多。我这次直接把2026年还能跑通的路径重新过了一遍,从准备工作到领取完成&…

2026/10/13 19:15:30 阅读更多 →
免费开源ERP系统选型与实施:进销存+财务+生产一体化实战指南

免费开源ERP系统选型与实施:进销存+财务+生产一体化实战指南

这几年在圈子里被问得最多的一个问题,就是中小公司和创业团队到底要不要上ERP。我的答案一直很干脆:要上,但别一上来就盯着那套贵得离谱的商业软件。免费开源的进销存财务生产ERP系统,这些年成熟度已经很高了,尤其适合…

2026/10/13 19:15:30 阅读更多 →
免费开源一体化ERP实战:进销存+财务+生产+SaaS部署与权限管理

免费开源一体化ERP实战:进销存+财务+生产+SaaS部署与权限管理

我一个干制造业信息化多年的人,这几年最深的感受就是:太多中小工厂被Excel管生产、管库存、管账的方式拖住了。业务一多,采购下单靠拍脑袋,仓库月底盘点对不上数,财务月底对账加班到深夜,生产领料不知道库存…

2026/10/13 19:15:30 阅读更多 →
多智能体电梯群控:基于目的楼层预约与PPO的深度强化学习实现

多智能体电梯群控:基于目的楼层预约与PPO的深度强化学习实现

简介:本资源是一套面向计算机、人工智能、自动化等专业学生的毕业设计与课程设计实践项目,聚焦于多智能体协同下的电梯群控优化问题,采用深度强化学习实现目的楼层预约调度算法,解决传统电梯响应延迟高、能耗大、乘客等待时间长等…

2026/10/13 19:14:30 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →