Android Jetpack Compose之状态持久化与恢复

目录

  • 1.概述
  • 2.实例解析
  • 4. Compose提供的MapSaver和ListSaver
    • 4.1 mapServer
    • 4.2 ListSaver

1.概述

在之前的文章中,我们提到了remember,我们都知道remember可以缓存创建状态,避免因为重组而丢失。使用remember缓存的状态虽然可以跨越重组,但是不能跨Activity或者跨进程。比如横竖屏切换等ConfigiurationChanged事件发生时,假设没有重写对应的onConfigurationChanged函数,Activity就会被销毁重建,导致remember保存的状态丢失。为了解决这个问题,Compose提供了rememberSavable,它可以像Activity的onSaveInstanceState那样在进程被杀死时自动保存状态,同时像onRestoreInstanceState一样随进程的重建而恢复。

2.实例解析

rememberSavable中的数据会随着onSaveInstanceState进行保存,并在进程或者是Activity重建时根据key恢复到对应的Composable中,这个key就是Composable在编译期间被确定的唯一标识。只有当用户手动退出的时候,rememberSavable中的数据才会被情况。

rememberSavable的实现原理实际上就是将数据以Bundle的形式保存,所以凡是Bundle支持的基本数据类型都是可以自动保存的。如果我们保存的是一个对象,那么需要变成一个Parcelable对象,比如我们要保存一个Person类,代码如下所示:

@Parcelize
data class Person(val name: String,val age: String
) : Parcelable

当为一个Parcelable接口的派生类添加@Parcelable时,Kotlin编译器会自动为其添加Parcelable的实现,使用@Parcelable注解时,需要添加kotlin-parcelize插件,在模块的build.gradle文件中对应地方添加如下的代码

plugins{id 'kotlin-parcelize'
}

测试的代码如下所示:

class ComposeCounterAct : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyComposeTheme {// A surface container using the 'background' color from the themeSurface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colorScheme.background) {GetPerson()}}}}@Composablefun GetPerson() {val person = rememberSaveable(key = "zxj") {mutableStateOf(Person("walt", 29))}Column {ShowText(person.value)Button(modifier = Modifier.wrapContentWidth().height(40.dp), onClick = {person.value = (Person("zhong", 30))}) {Text("修改数据!!!")}}}@Composablefun ShowText(person: Person) {Text(text = "name: ${person.name}===>${person.age}")}
}@Parcelize
data class Person(var name: String,var age: Int
) : Parcelable

在上面的代码中我们使用了rememberSaveable来保存了我们的Person对象,刚开始的时候给个初始值,主要是为了演示rememberSavable的功能,我们设置了一个按钮,点击按钮后person对象的对应属性会被修改,这时候如果我们让当前的activity被系统销毁重建,则会发现我们修改后的值不会被重置成默认的值,而如果使用remember的话,值会被重置。那么如何模拟当前的页面被系统回收呢?这里提供两个方法,一是不重写Activity的onConfigurationChanged(newConfig: Configuration)方法的情况下,旋转你的手机,这时Activity会被销毁重建。第二个方法是:在开发这选项中打开不保留后台活动的开关,然后退出应用再进入。以荣耀手机为例:

在这里插入图片描述

建议读者可以自己动手验证下,这里需要注意的是保留的数据能恢复只是在当前页面被系统回收的情况下会自动恢复,而用户手动退出,异常皆不会恢复之前的数据

#3. 自定义Saver
上一节我们说到,保存数据的类必须是一个Parcelable类,但是有的数据结构可能无法添加Parcelable接口,比如一些定义在三方类库中的类。对于这些类,我们可以使用自定义Saver为其实现保存和恢复的逻辑。只需要我们在调用rememberSavable时传入此Saver就行了,代码如下:

class ComposeCounterAct : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyComposeTheme {// A surface container using the 'background' color from the themeSurface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colorScheme.background) {GetPerson()}}}}@Composablefun GetPerson() {var person = rememberSaveable(stateSaver = PersonSaver) {mutableStateOf(Person("walt",29))}Column {ShowText(person.value)Button(modifier = Modifier.wrapContentWidth().height(40.dp), onClick = {person.value = (Person("zhong", 30))}) {Text("修改数据!!!")}}}@Composablefun ShowText(person: Person) {Text(text = "name: ${person.name}===>${person.age}")}}object PersonSaver:Saver<Person,Bundle>{override fun restore(value: Bundle): Person? {return value.getString("name")?.let {name->value.getInt("age").let { age->Person(name,age)}}}override fun SaverScope.save(value: Person): Bundle? {return Bundle().apply {putString("name",value.name)putInt("age",value.age)}}
}data class Person(var name: String,var age: Int
)

如上面的代码所示,我们去掉了Person的Parcelable实现,然后使用自定义的Saver完成状态的持久化和恢复,结果和上一节的相同。

4. Compose提供的MapSaver和ListSaver

4.1 mapServer

MapSaver将对象转换为Map<String,Any>的结构进行保存,注意value是可保存到Bundle的类型。
代码如下:

class ComposeCounterAct : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyComposeTheme {// A surface container using the 'background' color from the themeSurface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colorScheme.background) {GetPerson()}}}}@Composablefun GetPerson() {var person = rememberSaveable(stateSaver = personSaver) {mutableStateOf(Person("walt",29))}Column {ShowText(person.value)Button(modifier = Modifier.wrapContentWidth().height(40.dp), onClick = {person.value = (Person("zhong", 30))}) {Text("修改数据!!!")}}}@Composablefun ShowText(person: Person) {Text(text = "name: ${person.name}===>${person.age}")}}val personSaver = run {val nameKey = "name"val ageKey = "age"mapSaver(save = { mapOf(nameKey to it.name,ageKey to it.age) },restore = {Person(it[nameKey] as String,it[ageKey] as Int)})
}data class Person(var name: String,var age: Int
)

4.2 ListSaver

ListSaver是将对象转换为List的数据结构进行保存。将下面的代码替换上面的saver部分皆可,结果都是一样的,只是使用的方式不同,建议读者根据情况选用。

val personListSaver = listSaver<Person,Any>(save = { listOf(it.name,it.age) },restore = {Person(it[0] as String,it[1] as Int)}
)

注意: 假设只是需要状态跨越Configurationchagned而不需要跨进程恢复,那么我们可以在Androidmanifest.xml中设置android:configChanges,然后使用普通的remember即可。因为Compose能够在所有ConfigurationChanged发生时做出响应。但是理论上纯Compose项目是不需要因为ConfigurationChange重建Activity的,这里希望读者正确区分

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/137711.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打造生产级Llama大模型服务

对于任何想要尝试人工智能或本地LLM&#xff0c;又不想因为意外的云账单或 API 费用而感到震惊的人&#xff0c;我可以告诉你我自己的旅程是如何的&#xff0c;以及如何开始使用廉价的消费级硬件执行Llama2 推理 。 这个项目一直在以非常活跃的速度发展&#xff0c;这使得它非…

Call短路触发版本SIP对讲求助终端

SV-2701VP Call短路触发版本SIP对讲求助终端 一、描述 SV-2701VP是我司的一款壁挂式求助对讲终端&#xff0c;具有10/100M以太网接口&#xff0c;支持G.711与G.722音频解码&#xff0c;其接收SIP网络的音频数据&#xff0c;实时解码播放。配置一路线路输入&#xff0c;一路线…

《动手学深度学习 Pytorch版》 7.1 深度卷积神经网络(LeNet)

7.1.1 学习表征 深度卷积神经网络的突破出现在2012年。突破可归因于以下两个关键因素&#xff1a; 缺少的成分&#xff1a;数据 数据集紧缺的情况在 2010 年前后兴起的大数据浪潮中得到改善。ImageNet 挑战赛中&#xff0c;ImageNet数据集由斯坦福大学教授李飞飞小组的研究人…

MyBatis 分页插件 PageHelper

文章目录 前言PageHelper 应用实现原理剖析应用场景分析 前言 分页插件PageHelper是我们使用Mybatis到的比较多的插件应用&#xff0c;适用于任何复杂的单表、多表分页查询操作。本文介绍PageHelper的使用及原理。 PageHelper 应用 添加依赖 <dependency><groupId…

解决jupyter找不到虚拟环境的问题

解决jupyter找不到虚拟环境的问题 使用jupyter只能使用base环境&#xff0c;不能找到自己创建的虚拟环境。如下图&#xff0c;显示的默认的虚拟环境base的地址。 如何解决这个问题&#xff1f;需要两个步骤即可 1 . 在base环境中安装nb_conda_kernels这个库 activate base c…

【蓝桥杯选拔赛真题62】Scratch判断小球 少儿编程scratch图形化编程 蓝桥杯选拔赛真题解析

目录 scratch判断小球 一、题目要求 编程实现 二、案例分析 1、角色分析

浙大mpa项目提前批面试如果拿不到A资格怎么办?

2024年浙江大学MPA项目提前批面试申请已经结束&#xff0c;至今来看总的申请人数跟去年2023届基本相当&#xff0c;超过四百名学员报名提面&#xff0c;按照去年1923人报考的体量来看&#xff0c;大多数人恐怕还是把录取的希望保留到常规批复试中。那么&#xff0c;400提面考生…

LInux echo-tail-重定向符命令

①echo命令——输出指定内容 反引号&#xff08;飘号&#xff09; 重定向符 覆盖写入 追加写入 将目录写入txt.txt文件中 ②tail命令——查看文件尾部内容 这是txt.txt文件内容 默认查看尾部十行内容 查看倒数5行的内容 -f会持续追踪&#xff0c;只要有变化就动态显示

Qt DoubleSlider双滑块支持float变化的控件,以及单滑块float控件

Qt DoubleSlider 双滑块支持float变化的控件&#xff0c;以及单滑块float控件 - 一杯清酒邀明月 - 博客园 (cnblogs.com)https://www.cnblogs.com/ybqjymy/p/13813001.html参考别人的分享&#xff0c;双滑块 看一下效果&#xff1a;

服务器硬件监控解决方案,提升服务器稳定性

前言 在当今数字化时代&#xff0c;服务器的稳定运行对于企业的核心业务至关重要。为了确保服务器的正常运行并及时发现潜在问题&#xff0c;我们公司开发了一款先进的服务器硬件监控解决方案。本文将深入探讨服务器硬件监控的重要性、解决方案的特点和优势&#xff0c;以及支持…

ASO优化之如何给应用选择竞争对手

在选择竞争对手过程中&#xff0c;最常见的错误之一是没有考虑到自己的应用与同一行业的其他应用相比的范围。例如如果我们刚刚发布了一个应用程序&#xff0c;那么最好的办法就是专注于研究和自己同一级别的应用。 1、研究主要关键词。 首先选择5到10个可以定义产品类型的主要…

leetcode 周赛——2848. 与车相交的点

题目所属分类 差分数组知识点 原题链接 给你一个下标从 0 开始的二维整数数组 nums 表示汽车停放在数轴上的坐标。对于任意下标 i&#xff0c;nums[i] [starti, endi] &#xff0c;其中 starti 是第 i 辆车的起点&#xff0c;endi 是第 i 辆车的终点。 返回数轴上被车 任意…

语义分割——灰度图像转伪彩色图像

目录 检验灰度图检验代码 灰度图转伪彩色图代码转换代码使用细则 示例转换结果总结 检验灰度图 制作语义分割数据集或用训练好模型测试图像时&#xff0c;得到的结果是灰度图像&#xff0c;如下&#xff1a; 检验代码 上面图像灰度值不是全是全为0&#xff0c;灰度范围在[0…

MYSQL的触发器

触发器是与表有关的数据库对象&#xff0c;指在 insert/update/delete 之前 (BEFORE) 或之后 (AFTER) &#xff0c;触发并执行触发器中定义的SQL 语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性 , 日志记录 , 数据校验等操作 。使用别名OLD 和 NEW 来引用…

Docker镜像制作

Docker镜像制作 镜像制作 基本命令 容器转为镜像 docker commit 容器id 镜像名称:版本号 docker save -o 压缩文件名称 镜像名称:版本号 docker load -i 压缩文件名称实例操作 容器转为镜像 需要注意的是&#xff1a;制作镜像并不会把里面的目录挂载的文件写到镜像中 # 查看…

评价指标分类

声明 本文是学习GB-T 42874-2023 城市公共设施服务 城市家具 系统建设实施评价规范. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件确立了城市家具系统建设实施的评价原则、评价流程&#xff0c;给出了评价指标&#xff0c;描述了 方…

第 113 场 LeetCode 双周赛题解

A 使数组成为递增数组的最少右移次数 数据范围小直接模拟… class Solution { public:int minimumRightShifts(vector<int> &nums) {for (int op 0; op < nums.size(); op) {if (is_sorted(nums.begin(), nums.end()))//nums是否已经有序return op;rotate(nums.b…

Hive 的权限管理

目录 ​编辑 一、Hive权限简介 1.1 hive中的用户与组 1.1.1 用户 1.1.2 组 1.1.3 角色 1.2 使用场景 1.2.1 hive cli 1.2.2 hiveserver2 1.2.3 hcatalog api 1.3 权限模型 1.3.1 Storage Based Authorization in the Metastore Server 1.3.2 SQL Standards Based …

element树形组件使用之数据授权

<template><div><el-card class"tree-card"><p class"title">数据授权</p><div class"box"><div class"tree"><div class"member">选择授权人员</div><div class…

【python数据分析基础】—pandas中loc()与iloc()的介绍与区别

文章目录 前言一、loc[]函数二、iloc[]函数三、详细用法loc方法iloc方法 总结共同点不同点 前言 我们经常在寻找数据的某行或者某列的时常用到Pandas中的两种方法iloc和loc&#xff0c;两种方法都接收两个参数&#xff0c;第一个参数是行的范围&#xff0c;第二个参数是列的范…