Android 组件提供的状态保存(saveInstanceState)与恢复(restoreInstanceState)

news2024/12/21 19:04:16

Android的组件Activity中,有这样一对方法: onSaveInstanceeStateonRestoreInstanceState

这两对方法,可以让我在Activiy异常销毁时,保存状态;以及在Activity重建时,恢复状态。

比如:当我们在输入框中输入了内容,此时因为种种原因,将App退至了后台。这个处于后台的App很有可能因为内存不足、其他配置,被系统杀死。

当我们恢复这个页的时候,希望它能够保存住我们原来输入的内容。

除了,我们自己手动保存,也可以利用系统的onSaveInstanceStateonRestoreInstanceState

那么,在Android已有的系统中,是如何做的呢?

我们查阅EditText,发现它的父类TextView做了保存状态与恢复状态的处理,但是根据条件(freezesText || hasSelection)做了保存与恢复,如果只用TextView用于展示,并不会触发保存与恢复。

TextView的状态保存与恢复。

// 保存状态
@Override  
public Parcelable onSaveInstanceState() {  
	Parcelable superState = super.onSaveInstanceState();  
  
	// Save state if we are forced to  
	final boolean freezesText = getFreezesText();  
	boolean hasSelection = false;  
	int start = -1;  
	int end = -1;  
  
	if (mText != null) {  
		start = getSelectionStart();  
		end = getSelectionEnd();  
		if (start >= 0 || end >= 0) {  
			// Or save state if there is a selection  
			hasSelection = true;  
		}  
	}  
	// 满足此条件时,才进行保存数据
	if (freezesText || hasSelection) {  
		SavedState ss = new SavedState(superState);  
  
		if (freezesText) {  
			if (mText instanceof Spanned) {  
				final Spannable sp = new SpannableStringBuilder(mText);  
		  
				if (mEditor != null) {  
					removeMisspelledSpans(sp);  
					sp.removeSpan(mEditor.mSuggestionRangeSpan);  
				}  
				ss.text = sp;  
			} else {  
				ss.text = mText.toString();  
			}  
		}  
  
		if (hasSelection) {  
			// XXX Should also save the current scroll position!  
			ss.selStart = start;  
			ss.selEnd = end;  
		}  
	  
		if (isFocused() && start >= 0 && end >= 0) {  
			ss.frozenWithFocus = true;  
		}  
	  
		ss.error = getError();  
	  
		if (mEditor != null) {  
			ss.editorState = mEditor.saveInstanceState();  
		}  
		return ss;  
	}  
  
	return superState;  
}

// 恢复状态
@Override  
public void onRestoreInstanceState(Parcelable state) {  
	if (!(state instanceof SavedState)) {  
		super.onRestoreInstanceState(state);  
		return;  
	}  
  
	SavedState ss = (SavedState) state;  
	super.onRestoreInstanceState(ss.getSuperState());  
  
	// XXX restore buffer type too, as well as lots of other stuff  
	if (ss.text != null) {  
		setText(ss.text);  
	}  
  
	if (ss.selStart >= 0 && ss.selEnd >= 0) {  
		if (mSpannable != null) {  
			int len = mText.length();  
  
			if (ss.selStart > len || ss.selEnd > len) {  
				String restored = "";  
  
				if (ss.text != null) {  
					restored = "(restored) ";  
				}  
  
				Log.e(LOG_TAG, "Saved cursor position " + ss.selStart + "/" + ss.selEnd  
				+ " out of range for " + restored + "text " + mText);  
			} else {  
				Selection.setSelection(mSpannable, ss.selStart, ss.selEnd);  
				if (ss.frozenWithFocus) {  
					createEditorIfNeeded();  
					mEditor.mFrozenWithFocus = true;  
				}  
			}  
		}  
	}  
  
	if (ss.error != null) {  
		final CharSequence error = ss.error;  
		// Display the error later, after the first layout pass  
		post(new Runnable() {  
				public void run() {  
					if (mEditor == null || !mEditor.mErrorWasChanged) {  
						setError(error);  
					}  
				}  
			});  
	}  
  
	if (ss.editorState != null) {  
		createEditorIfNeeded();  
		mEditor.restoreInstanceState(ss.editorState);  
	}  
}

onSaveInstanceState&onRestoreInstanceState的执行时机

这两个函数在什么情况下使用?比如开发者模式中开启了不保留活动、屏幕方向发生改变等原因,导致Activity(视图)被销毁或重建时,会执行。

被销毁时,执行onSaveInstanceState
重建时,执行onRestoreInstanceState

当然,这两个函数的执行也是有一些条件的,比如,View必须指定了Id,Id在整个视图(PhoneWindow)内必须唯一,如果不唯一则会在恢复状态时报错(保存时不会报错)。

在View的默认实现中,如果发现id一样,则会在恢复状态时报错。

@CallSuper  
protected void onRestoreInstanceState(Parcelable state) {  
	mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;  
	if (state != null && !(state instanceof AbsSavedState)) {  
		throw new IllegalArgumentException("Wrong state class, expecting View State but "  
		+ "received " + state.getClass().toString() + " instead. This usually happens "  
		+ "when two views of different type have the same id in the same hierarchy. "  
		+ "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure "  
		+ "other views do not use the same id.");  
}
// …… 省略剩余代码
}

我们在自定义View和使用第三方控件等情况下,需要合理处理这两个函数,否则会导致崩溃。

这里附一张InstanceState的执行时机图:

在这里插入图片描述

save的状态保存在哪里?restore的数据怎么取?

在View中,执行了onSaveInstanceState()后,View会将获取到的结果,保存在一个SparseArray中,这个SparseArray是从最根部的PhoneWindow中传递进来的,整个PhoneWindow中只有一份。

view中执行,container.put(mID, state);就会把自己要保存的数据放置到SparseArray中。

如果视图中存在id相同的View,那么后面保存的替换掉之前保存的。

在恢复数据时,也是从SparseArray中以当前View的Id为可以,获取保存的数据。获取到就是上一次保存时最后存储的数据。

Parcelable state = container.get(mID);  
if (state != null) {  
	// ……
	onRestoreInstanceState(state);
	// ……
}

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

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

相关文章

MATLAB 2024a软件下载安装教程

1-首先下载Matlab,以下迅雷云链接,里面有全版本的matlab,根据自己的需要下载即可,建议下载最新版的,功能会更多,当然内存也会更大。 迅雷云盘迅雷云盘https://pan.xunlei.com/s/VNgH_6VFav8Kas-tRfxAb3XOA…

Linux I2C(二) - I2C软硬件架构

1,I2C的总线拓扑 2,I2C S/W topology linux kernel I2C framework使用如下的软件拓扑抽象I2C硬件(我们可以一起领会一下其中的“设备模型”思想): 1)platform bus(/sys/bus/platform&#xff0…

Oracle导出导入dmp等文件类型的多表数据的常用方法、遇见的常见问题和解决办法(exp无效sql???)

使用PLSQL执行导出表数据的时候有两种方法 1、使用Oracle命令【imp--exp】【impdp--expdp】 但是如果你的本机没有安装有Oracle数据库,使用的instant client远程连接服务器上的Oracle数据库时候,你没有Oracle数据库带有的exp.exe、imp.exe等扩展文件&a…

如何高效跟进项目进度?试试禅道几个功能

禅道提供了一系列功能和工具,可实现项目进度的有效管理和跟进,极大提升项目管理效率。禅道中的项目进度来源于迭代进度,迭代的进度又来源于任务的消耗和剩余工时,可通过以下功能有效跟进项目进展。 一、燃尽图 在禅道里&#xf…

机器学习day1

一、人工智能三大概念 人工智能三大概念 人工智能(AI)、机器学习(ML)和深度学习(DL) 人工智能:人工智能是研究计算代理的合成和分析的领域。人工智能是使用计算机来模拟,而不是人类…

【办公类-22-14】周计划系列(5-5)“周计划-05 周计划表格内教案部分“节日”清空改成“节日“” (2024年调整版本)Win32

背景需求: 本学期19周,用了近10周的时间,终于把周计划教案部分的内容补全了(把所有教案、反思的文字都撑满一个单元格), 一、原始教案 二、新模板内的教案 三、手动添加文字后的样式(修改教案…

庐山研习班上介绍的25个LINUX工具

从2013年的第一届算起,庐山研习班走过十余个年头,办了十几次了。但每一次,都有很多不一样。即使是相同的主题,也有很大差异。 今年春季的庐山研习班是在上个周末。周四晚上我和大部分同学都到了五老峰脚下的训练基地。 除了周六下…

【C++ STL序列容器】list 双向链表

文章目录 【 1. 基本原理 】【 2. list 的创建 】2.1 创建1个空的 list2.2 创建一个包含 n 个元素的 list(默认值)2.3 创建一个包含 n 个元素的 list(赋初值)2.4 通过1个 list 初始化另一个 list2.5 拷贝其他类型容器的指定元素创…

HNCTF 2022 week1 题解

自由才是生活主旋律。 [HNCTF 2022 Week1] Interesting_include <?php //WEB手要懂得搜索 //flag in ./flag.phpif(isset($_GET[filter])){$file $_GET[filter];if(!preg_match("/flag/i", $file)){die("error");}include($file); }else{highlight_…

CentOS7安装并配置Yearning并实现无公网IP远程SQL审核与数据查询

目录 ​编辑 前言 1. Linux 部署Yearning 2. 本地访问Yearning 3. Linux 安装cpolar 4. 配置Yearning公网访问地址 5. 公网远程访问Yearning管理界面 6. 固定Yearning公网地址 结语 前言 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊…

Docker 的数据管理 端口映射 容器互联 镜像的创建

目录 概念 概念 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&#xff09;。总结&#xff1a;因为容器数据是临时保存的为了安全&#xff0c;就要让数据保持持久化。 1&#…

qt QTreeWidget 学习

树形控件的节点可以有多层、多个子节点&#xff0c; 如果将子节点全部展开&#xff0c;那么每一行都是一个数据条目。QTreeWidgetItem 比较特殊&#xff0c;一个条目内部可以有多列数据信息&#xff0c;相当于表格控件一整行的表格单元集成为一个条目。 默认情况下&#xff0c;…

Methoxy-PEG-PLGA,mPEG-PLGA是一种可生物降解的两亲性嵌段共聚物

【试剂详情】 英文名称 mPEG-PLGA&#xff0c;Methoxy-PEG-Poly(lactide-co-glycolide)&#xff0c;Methoxy-PEG-PLGA&#xff0c; mPEG-Poly(lactide-co-glycolide) 中文名称 聚乙二醇单甲醚聚乳酸&#xff0c;乙醇酸两嵌段共聚物 外观性状 由分子量决定&#xff0c;液体…

调试记录 Flash 芯片 GD25LQ128ESIG 的程序烧录问题

1. 烧录工具 工具型号&#xff1a; VS4000P 2. 烧录问题 1. 烧录器选择烧录型号过程中没有看见 Flash 芯片 GD25LQ128ESIG 的型号。其中有GD25Q128E &#xff0c;但是三个选项的封装不对。 3. 解决过程 1. 尝试别的类型的芯片型号烧录。 A.GD25LQ80E(SOP8_200) B.GD25LQ64E(SOP…

IDEA 2024.1 配置 AspectJ环境

最近Java课设在学习AspectJ&#xff0c;做PPT顺便写一个博客 下载包 首先去AspectJ官网下载一个JAR包并安装 安装完最后可以按照他的建议配置一下 然后找到AspectJ的安装位置的lib目录&#xff0c;把三个包拷到自己项目中的lib目录下 由于最新版的IDEA已经不支持AspectJ了 所…

(八)Servlet教程——创建Web项目以及Servlet的实现

1. 打开Idea编辑器 2. 点击界面上的“新建项目”按钮 3. 设置好项目名称和位置 应用服务器选择之前设置好的Tomcat服务器 构建系统默认选择Maven 4. 点击“下一步”按钮 5. 点击“完成”按钮&#xff0c;Idea就创建好了项目&#xff0c;创建完成后的目录结构如下图所示 6. 此…

脉冲电源的直流斩波板设计总结(RC缓冲电路,输出电容选值)

IC的RC缓冲 总结一下过去电加工所的直流斩波板问题 1&#xff1a;电流突变问题 在独立式电火花脉冲电源里面&#xff0c;用电阻去限制电流&#xff0c;从而抑制当极间突变时的电流突变。 在非独立式的脉冲电源里面&#xff0c;电流平时是稳定在循环电感里面&#xff0c;当击…

ESLlint重大更新后,使用旧版ESLint搭配Prettier的配置方式

概要 就在前几天&#xff0c;ESLint迎来了一次重大更新&#xff0c;9.0.0版本&#xff0c;根据官方文档介绍&#xff0c;使用新版的先决条件是Node.js版本必须是18.18.0、20.9.0&#xff0c;或者是>21.1.0的版本&#xff0c;新版ESLint将不再直接支持以下旧版配置(非扁平化…

USB设备的音频类UAC

一、UAC简介 UAC&#xff08;USB Audio Class&#xff09;是USB设备的音频类&#xff0c;它定义了USB音频设备与主机计算机通信的方式。UAC标准是USB规范的一部分&#xff0c;并受到各种操作系统&#xff08;包括Windows、macOS和Linux&#xff09;的支持。 UAC是基于libusb,实…

抖音智能运营系统源码

这是一个一站式服务的抖音智能运营系统&#xff0c;旨在提升内容创作者和营销人员的工作效率。它是一个综合性的在线服务平台&#xff0c;专为抖音内容创作者和营销人员设计。系统基于高性能、可扩展性强的ThinkPHP框架&#xff0c;整合了视频处理、数据分析、文案生成与配音等…