Android 开发避坑经验第四篇:正确处理Activity和Fragment的状态保存与恢复

在 Android 开发中,​​Activity​​ 和 ​​Fragment​​ 的状态保存与恢复是一个常见的坑点。如果处理不当,可能会导致应用在屏幕旋转、后台恢复等场景下出现数据丢失、UI 状态不一致等问题。本篇文章将详细探讨如何正确保存和恢复 ​​Activity​​ 与 ​​Fragment​​ 的状态,并提供最佳实践的代码示例。

1. 坑点:Activity 和 Fragment 的重建导致数据丢失

当用户旋转屏幕或者系统回收内存时,​​Activity​​ 或 ​​Fragment​​ 可能会被销毁并重建。如果没有妥善处理状态保存,这将导致用户输入或显示的数据丢失,影响用户体验。

避坑建议:
  • 使用 ​​onSaveInstanceState()​​ 方法来保存 ​​Activity​​ 或 ​​Fragment​​ 的状态。
  • 避免通过构造函数传递数据,改用 ​​Bundle​​ 或 ​​ViewModel​​ 来保存和恢复状态。
  • 对于重要的数据(如用户输入、临时状态等),应保存到 ​​Bundle​​ 中。
示例代码:
class MainActivity : AppCompatActivity() {private var userInput: String? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 恢复状态userInput = savedInstanceState?.getString("user_input")findViewById<TextView>(R.id.textView).text = userInput}override fun onSaveInstanceState(outState: Bundle) {super.onSaveInstanceState(outState)// 保存状态outState.putString("user_input", userInput)}
}

解释: 在 ​​onCreate()​​ 中,通过 ​​savedInstanceState​​ 检查是否有已保存的状态,确保在重建 ​​Activity​​ 后可以正确恢复用户的输入状态。通过 ​​onSaveInstanceState()​​,我们可以在 ​​Activity​​ 被销毁前保存数据,避免用户输入的内容丢失。

2. 坑点:Fragment 状态保存不当导致数据丢失

与 ​​Activity​​ 类似,​​Fragment​​ 的状态保存和恢复也需要通过 ​​onSaveInstanceState()​​ 方法。但由于 ​​Fragment​​ 可能会与 ​​Activity​​ 共享数据,状态的保存和恢复过程可能更加复杂。

避坑建议:
  • 使用 ​​Fragment​​ 的 ​​setArguments()​​ 方法传递初始数据,而不是直接通过构造函数传递。
  • 在 ​​onSaveInstanceState()​​ 中保存 ​​Fragment​​ 的重要状态,并在 ​​onCreateView()​​ 或 ​​onViewCreated()​​ 中恢复这些状态。
示例代码:
class MyFragment : Fragment() {private var data: String? = nulloverride fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {val view = inflater.inflate(R.layout.fragment_layout, container, false)// 恢复状态data = savedInstanceState?.getString("saved_data")view.findViewById<TextView>(R.id.textView).text = datareturn view}override fun onSaveInstanceState(outState: Bundle) {super.onSaveInstanceState(outState)// 保存状态outState.putString("saved_data", data)}companion object {fun newInstance(data: String): MyFragment {val fragment = MyFragment()val args = Bundle()args.putString("initial_data", data)fragment.arguments = argsreturn fragment}}
}

解释: 通过 ​​onSaveInstanceState()​​ 保存 ​​Fragment​​ 的状态,并在 ​​onCreateView()​​ 中恢复数据,可以确保 ​​Fragment​​ 在配置变化或重建时能够保持正确的状态。​​newInstance()​​ 方法通过 ​​Bundle​​ 传递数据,避免了直接通过构造函数传递数据的潜在问题。

3. 坑点:ViewModel 的使用不当导致内存泄漏

​ViewModel​​ 是 Android Jetpack 提供的一个强大工具,专门用于管理 UI 相关的数据。它能够在配置变化(如屏幕旋转)时保留数据。但如果使用不当,可能会导致内存泄漏,特别是在 ​​ViewModel​​ 中持有 ​​Context​​ 或 UI 元素的引用时。

避坑建议:
  • 避免在 ​​ViewModel​​ 中持有 ​​Context​​、​​Activity​​ 或 ​​Fragment​​ 的直接引用。
  • 如果需要使用 ​​Context​​,使用 ​​AndroidViewModel​​ 或通过 ​​Application Context​​ 获取全局上下文。
  • 当 ​​Activity​​ 或 ​​Fragment​​ 销毁时,确保及时清理与 ​​ViewModel​​ 的引用。
示例代码:
class MyViewModel(application: Application) : AndroidViewModel(application) {private val _data = MutableLiveData<String>()val data: LiveData<String> get() = _datafun loadData() {// 模拟从全局上下文中加载数据val context = getApplication<Application>().applicationContext_data.value = "Loaded data from context"}
}

解释: ​​AndroidViewModel​​ 提供了一个安全的方式来获取 ​​Application Context​​,避免了直接持有 ​​Activity​​ 或 ​​Fragment​​ 的引用,从而防止内存泄漏。

4. 坑点:复杂对象的状态保存

​Bundle​​ 的大小是有限的,存储过大的数据对象可能会导致 ​​TransactionTooLargeException​​,从而导致应用崩溃。这是开发者在保存复杂对象时常遇到的问题。

避坑建议:
  • 避免将过大的对象(如图像、大型数据列表)直接存入 ​​Bundle​​。
  • 对于大型数据,可以考虑使用 ​​ViewModel​​ 或者 ​​onRetainCustomNonConfigurationInstance()​​ 来保存数据。
  • 对于无法序列化的对象(如自定义类),应通过数据库或文件系统保存,避免将其存入 ​​Bundle​​。
示例代码:
class MyActivity : AppCompatActivity() {private lateinit var largeData: List<MyData>override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 从ViewModel或其他持久化存储中恢复数据val viewModel = ViewModelProvider(this).get(MyViewModel::class.java)largeData = viewModel.getLargeData()}
}class MyViewModel : ViewModel() {private var largeData: List<MyData>? = nullfun getLargeData(): List<MyData> {if (largeData == null) {// 模拟从数据源加载数据largeData = loadDataFromDatabase()}return largeData!!}
}

解释: 在该代码中,通过 ​​ViewModel​​ 来保存和恢复大型数据,避免了将大型数据直接存入 ​​Bundle​​ 导致的崩溃风险。​​ViewModel​​ 的生命周期与 ​​Activity​​ 和 ​​Fragment​​ 绑定,适合处理这种场景。

结论

在 Android 开发中,正确处理 ​​Activity​​ 和 ​​Fragment​​ 的状态保存与恢复是保证应用稳定性和用户体验的关键。通过使用 ​​onSaveInstanceState()​​、​​ViewModel​​ 等技术,开发者可以避免常见的状态丢失、内存泄漏以及性能问题。这篇文章希望能帮助开发者在实际项目中更加顺利地应对这些坑点,提升应用质量。

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

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

相关文章

官宣:Zilliz 在亚马逊云科技中国区正式开服!

01 Zilliz Cloud 正式上线亚马逊云科技宁夏区服务 9 月 4 日&#xff0c;Zilliz 正式官宣&#xff0c; Zilliz Cloud 正式上线亚马逊云科技在宁夏区的云服务。至此&#xff0c;Zilliz Cloud 已实现全球 5 大云 19 个节点 的全覆盖&#xff0c;成为全球首个提供海内外多云服务的…

《机器学习》—— SVD奇异值分解方法对图像进行压缩

文章目录 一、SVD奇异值分解简单介绍二、代码实现—SVD奇异值分解方法对图像进行压缩 一、SVD奇异值分解简单介绍 SVD&#xff08;奇异值分解&#xff09;是一种在信号处理、统计学、线性代数、机器学习等多个领域广泛应用的矩阵分解方法。它将任何 mn 矩阵 A 分解为三个特定矩…

从0书写一个softmax分类 李沐pytorch实战

输出维度 在softmax 分类中 我们输出与类别一样多。 数据集有10个类别&#xff0c;所以网络输出维度为10。 初始化权重和偏置 torch.norma 生成一个均值为 0&#xff0c;标准差为0.01,一个形状为size(num_inputs, num_outputs)的张量偏置生成一个num_outputs 10 的一维张量&a…

Kubernetes从零到精通(10-服务Service)

Service简介 Deployment这种工作负载能管理我们应用Pod的副本数&#xff0c;并实现动态的创建和销毁&#xff0c;所以Pod本身是临时资源&#xff08;IP随时可能变化&#xff09;。现在如果某组Pod A需要访问另一组Pod B&#xff0c;A就需要在应用的配置参数里动态跟踪并更改B的…

【数学建模】相关系数

第一部分&#xff1a;相关系数简介 总体与样本&#xff1a; 总体&#xff1a;指研究对象的全体&#xff0c;比如全国人口普查数据。样本&#xff1a;从总体中抽取的一部分个体&#xff0c;如通过问卷调查收集的学生数据。 皮尔逊相关系数&#xff1a; 总体皮尔逊相关系数&…

Linux 8250串口控制器

1 8250串口类型的识别 Intel HW都使用DesignWare 8250&#xff1a; drivers/mfd/intel-lpss-pci.c drivers/tty/serial/8250/8250_dw.c IIR寄存器的高2位bit7、bit6用来识别8250串口的类型&#xff1a; 0 - 8250&#xff0c;无FIFO 0 - 并且存在SCR&#xff08;Scratch registe…

安科瑞Acrel-1000DP分布式光伏监控系统平台的设计与应用-安科瑞 蒋静

针对用户新能源接入后存在安全隐患、缺少有效监控、发电效率无法保证、收益计算困难、运行维护效率低等通点&#xff0c;提出的Acrel-1000DP分布式光伏监控系统平台&#xff0c;对整个用户电站全面监控&#xff0c;为用户实现降低能源使用成本、减轻变压器负载、余电上网&#…

如何构建大数据治理平台,助力企业数据决策

建设背景 &#xff08;1&#xff09;什么是数据资产 资产由企业及组织拥有和控制&#xff0c;能够提供增值服务、带来经济利益的重要资源。 资产不但需要管理&#xff0c; 更需要运营。 &#xff08;2&#xff09;数据资产运营中的问题 数据资产运营中存在的问题主要包括以下…

CANopen协议的理解

本文的重点是对CANopen协议的理解&#xff0c;不是编程实现 参考链接 canopen快速入门 1cia301协议介绍_哔哩哔哩_bilibili CANopen是什么&#xff1f; CANopen通讯基础&#xff08;上&#xff09;_哔哩哔哩_bilibili CANopen概述 图1. CAN报文标准帧的格式 CAN的报文可简单…

docker-compose 部署 flink

下载 flink 镜像 [rootlocalhost ~]# docker pull flink Using default tag: latest latest: Pulling from library/flink 762bedf4b1b7: Pull complete 95f9bd9906fa: Pull complete a880dee0d8e9: Pull complete 8c5deab9cbd6: Pull complete 56c142282fae: Pull comple…

Redis搭建集群

功能概述 Redis Cluster是Redis的自带的官方分布式解决方案&#xff0c;提供数据分片、高可用功能&#xff0c;在3.0版本正式推出。 使用Redis Cluster能解决负载均衡的问题&#xff0c;内部采用哈希分片规则&#xff1a; 基础架构图如下所示&#xff1a; 图中最大的虚线部分…

路由器WAN口和LAN口有什么不一样?

“ 路由器WAN口和LAN口的区别&#xff0c;WAN是广域网端口&#xff0c;LAN是本地网端口。WAN主要用于连接外部网络&#xff0c;而LAN用来连接家庭内部网络&#xff0c;两者主要会在标识上面有区别。以往大部分路由器的WAN只有一个&#xff0c;LAN口则有四个或以上&#xff0c;近…

《深度学习》—— 神经网络基本结构

前言 深度学习是一种基于神经网络的机器学习算法&#xff0c;其核心在于构建由多层神经元组成的人工神经网络&#xff0c;这些层次能够捕捉数据中的复杂结构和抽象特征。神经网络通过调整连接各层的权重&#xff0c;从大量数据中自动学习并提取特征&#xff0c;进而实现预测或…

Banana Pi BPI-SM9 AI 计算模组采用算能科技BM1688芯片方案设计

产品概述 香蕉派 Banana Pi BPI-SM9 16-ENC-A3 深度学习计算模组搭载算能科技高集成度处理器 BM1688&#xff0c;功耗低、算力强、接口丰富、兼容性好。支持INT4/INT8/FP16/BF16/FP32混合精度计算&#xff0c;可支持 16 路高清视频实时分析&#xff0c;灵活应对图像、语音、自…

Python面试宝典第48题:找丑数

题目 我们把只包含质因子2、3和5的数称作丑数&#xff08;Ugly Number&#xff09;。比如&#xff1a;6、8都是丑数&#xff0c;但14不是&#xff0c;因为它包含质因子7。习惯上&#xff0c;我们把1当做是第一个丑数。求按从小到大的顺序的第n个丑数。 示例 1&#xff1a; 输入…

基于MinerU的PDF解析API

基于MinerU的PDF解析API - MinerU的GPU镜像构建 - 基于FastAPI的PDF解析接口支持一键启动&#xff0c;已经打包到镜像中&#xff0c;自带模型权重&#xff0c;支持GPU推理加速&#xff0c;GPU速度相比CPU每页解析要快几十倍不等 主要功能 删除页眉、页脚、脚注、页码等元素&…

uniapp使用高德地图设置marker标记点,后续根据接口数据改变某个marker标记点,动态更新

最近写的一个功能属实把我难倒了,刚开始我请求一次数据获取所有标记点,然后设置到地图上,然后后面根据socket传来的数据对这些标记点实时更新,改变标记点的图片或者文字, 1:第一个想法是直接全量替换,事实证明这样不行,会很卡顿,有明显闪烁感,如果标记点比较少,就十几个可以用…

【网络安全】-rce漏洞-pikachu

rce漏洞包含命令执行漏洞与代码执行漏洞 文章目录 前言 什么是rce漏洞&#xff1f; 1.rce漏洞产生原因&#xff1a; 2.rce的分类&#xff1a; 命令执行漏洞&#xff1a; 命令拼接符&#xff1a; 常用函数&#xff1a; 代码执行漏洞&#xff1a; 常用函数&#xff1a; 分类&…

信号与线性系统综合实验

文章目录 一、实验目的二、实验内容及其结果分析&#xff08;一&#xff09;基础部分&#xff08;二&#xff09;拓展部分&#xff08;三&#xff09;应用设计部分 三、心得体会 一、实验目的 1、掌握连续时间信号与系统的时域、频域综合分析方法&#xff1b;   2、掌握运用M…

SAP B1 单据页面自定义 - 用户界面编辑字段

背景 接《SAP B1 基础实操 - 用户定义字段 (UDF)》&#xff0c;在设置完自定义字段后&#xff0c;如下图&#xff0c;通过打开【用户定义字段】可打开表单右侧的自定义字段页。然而再开打一页附加页面操作繁复&#xff0c;若是客户常用的定义字段&#xff0c;也可以把这些用户…