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

Android中级——Activity数据恢复过程

Activity数据恢复

  • onSaveInstanceState()
  • onRestoreInstanceState()
  • 扩展

onSaveInstanceState()

在Activity调用onStop()之前调用会onSaveInstanceState(),如下

final void performStopActivity(IBinder token, boolean saveState, String reason) {ActivityClientRecord r = mActivities.get(token);performStopActivityInner(r, null /* stopInfo */, saveState, false /* finalStateRequest */,reason);
}private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean saveState, boolean finalStateRequest, String reason) {......callActivityOnStop(r, saveState, reason);......
}private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) {......final boolean shouldSaveState = saveState && !r.activity.mFinished && r.state == null && !r.isPreHoneycomb();final boolean isPreP = r.isPreP();if (shouldSaveState && isPreP) {callActivityOnSaveInstanceState(r);}try {r.activity.performStop(r.mPreserveWindow, reason);}......
}

onSaveInstanceState()存储Window视图树、调用Fragment、ActivityLifecycleCallbacks的onSaveInstanceState()

protected void onSaveInstanceState(@NonNull Bundle outState) {outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);Parcelable p = mFragments.saveAllState();if (p != null) {outState.putParcelable(FRAGMENTS_TAG, p);}if (mAutoFillResetNeeded) {outState.putBoolean(AUTOFILL_RESET_NEEDED, true);getAutofillManager().onSaveInstanceState(outState);}dispatchActivitySaveInstanceState(outState);
}

上面调用到PhoneWindow的saveHierarchyState()

@Override
public Bundle saveHierarchyState() {Bundle outState = new Bundle();if (mContentParent == null) {return outState;}SparseArray<Parcelable> states = new SparseArray<Parcelable>();mContentParent.saveHierarchyState(states);	outState.putSparseParcelableArray(VIEWS_TAG, states);	//存储视图树的结构final View focusedView = mContentParent.findFocus();if (focusedView != null && focusedView.getId() != View.NO_ID) {outState.putInt(FOCUSED_ID_TAG, focusedView.getId());	//存储当前焦点所在View的ID,持有焦点的View必须设置ID,否则无法恢复}SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();savePanelState(panelStates);if (panelStates.size() > 0) {outState.putSparseParcelableArray(PANELS_TAG, panelStates);	//存储面板信息}if (mDecorContentParent != null) {SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();mDecorContentParent.saveToolbarHierarchyState(actionBarStates);outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);	//存储actionBar}return outState;
}

mContentParent即是Activity中setContentView()所设置的根布局,调用到View的saveHierarchyState()方法

public void saveHierarchyState(SparseArray<Parcelable> container) {dispatchSaveInstanceState(container);
}

若当前是ViewGroup,则遍历child调用其dispatchSaveInstanceState()

@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {super.dispatchSaveInstanceState(container);final int count = mChildrenCount;final View[] children = mChildren;for (int i = 0; i < count; i++) {View c = children[i];if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {c.dispatchSaveInstanceState(container);}}
}

若当前是View,则从onSaveInstanceState()获取state根据当前View的ID保存到SparseArray

protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;Parcelable state = onSaveInstanceState();......if (state != null) {......container.put(mID, state);}}
}

onSaveInstanceState()需要由子类自身去实现,以TextView为例,保存了字符串、间距、位置信息等

@Override
public Parcelable onSaveInstanceState() {Parcelable superState = super.onSaveInstanceState();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) {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) {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;
}

onRestoreInstanceState()

在performLaunchActivity()中,取出ActivityClientRecord中的state传给Activity的OnCreate()方法,在正常启动时,state为空,需要对state进行判空

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {try {......if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}......r.activity = activity;} ......synchronized (mResourcesManager) {mActivities.put(r.token, r);}}......return activity;
}

在handleStartActivity()中先调用onStart(),再调用OnRestoreInstanceState()

@Override
public void handleStartActivity(IBinder token, PendingTransactionActions pendingActions) {final ActivityClientRecord r = mActivities.get(token);final Activity activity = r.activity;......activity.performStart("handleStartActivity");......if (pendingActions.shouldRestoreInstanceState()) {if (r.isPersistable()) {if (r.state != null || r.persistentState != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,r.persistentState);}} else if (r.state != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);}}......
}

扩展

Activity并非每次退出都会调用onSaveInstanceState(),如当用户按Back键主动退出时,下面列举几种调用onSaveInstanceState()的情况

  • 按下Home键
  • 长按Home键选中运行其他程序
  • 按下电源键息屏
  • 从Activity启动一个新的Activity
  • 屏幕方向切换
  • 电话打入

相关文章:

Android中级——Activity数据恢复过程

Activity数据恢复 onSaveInstanceState()onRestoreInstanceState()扩展 onSaveInstanceState() 在Activity调用onStop()之前调用会onSaveInstanceState()&#xff0c;如下 final void performStopActivity(IBinder token, boolean saveState, String reason) {ActivityClient…...

国内就能使用的chatgpt网页版,包含AIGC应用工具

Chatgpt的出现在多个领域带来了重要的影响。它能够显著提高我们的工作效率&#xff0c;无论是编写文案代码还是回答常见问题&#xff0c;都能在短时间内完成任务。通过Chatgpt&#xff0c;我们能够迅速获取所需答案。随着人工智能技术的不断发展&#xff0c;相信在未来AI能够带…...

Fast DDS之RTPS

目录 RTPS的使用 RTPS层实现了RTPS标准。DDS层概念映射关系如下&#xff1a; DDS LayerRTPS LayerDomainRTPSDomainDomainParticipantRTPSParticipantDataWriterRTPSWriterDataReaderRTPSReader RTPS的使用...

【算法|动态规划No.16】leetcode931. 下降路径最小和

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…...

Jenkins 构建时动态获取参数

文章目录 问题简介Groovy 脚本配置进阶 问题 在做jenkins项目时&#xff0c;有些参数不是固定写死的&#xff0c;而是动态变化的&#xff0c;这时我们可以用 Active Choices 插件来远程调用参数 问题解决方案&#xff1a;执行构建前使用Groovy Scrip调用本地脚本&#xff0c;…...

android app开机自启动

参考文章&#xff1a; Android APP开机启动&#xff0c;安卓APP开发自启动&#xff0c;安卓启动后APP自动启动 Android让程序开机自动运行APP_安卓应用开机启动并打开软件_weijia3624的博客-CSDN博客...

XSS CSRF

XSS & CSRF xss&#xff1a;跨站脚本攻击&#xff1a;注入一些非法的脚本 csrf&#xff1a;冒充身份 XSS 反射型 /welcome&#xff1a;res.send(req.query.type) 输入什么就输出什么&#xff08;httpOnly:false&#xff0c;但不是解决方案&#xff09; 比如&#xff1a;?&…...

新加坡星银行项目组笔试题面试题

Java/Fullstack___开发常见问题收集&#xff1a;&#xff08;根据个人面试岗位进行参考&#xff09; 项目介绍部分 介绍最近做过的项目&#xff0c;项目中遇到的印象深刻的问题&#xff0c;如何解决&#xff1f;就项目用到的技术&#xff0c;自己的技术以及如何使用&#xff1…...

基于SpringBoot的智能物流管理系统

目录 前言 一、技术栈 二、系统功能介绍 顾客信息管理 员工信息管理 员工信息管理 门店信息管理 门店信息管理 订单信息管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施…...

【开源电商网站】(2),使用docker-compose和dockerfile进行配置,设置自定义的镜像,安装插件,增加汉化包,支持中文界面汉化。

项目相关代代码地址 相关内容&#xff1a; https://blog.csdn.net/freewebsys/category_12461196.html 原文地址&#xff1a; https://blog.csdn.net/freewebsys/article/details/133666433 包括以下运行的详细代码&#xff1a; https://gitee.com/study-demo-all/oscommerc…...

HTML5开发实例-3D全景(ThreeJs全景Demo) 详解(图)

前言 在现在市面上很多全景H5的环境下,要实现全景的方式有很多,可以用css3直接构建也可以用基于threeJs的库来实现,还有很多别的制作全景的软件使用 本教学适用于未开发过3D全景的工程狮 如果觉得内容太无聊可以直接跳到最后 下载代码 理论 整个3D全景所用的相关理论就…...

springboot项目静态资源映射

1. springboot项目静态资源映射 import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import...

【Linux初阶】多线程1 | 页表的索引作用,线程基础(优缺点、异常、用途),线程VS进程,线程控制,C++多线程引入

文章目录 ☀️一、深入理解页表☀️二、Linux线程概念&#x1f33b;1.什么是线程&#xff08;重点&#xff09;⚡&#xff08;1&#xff09;线程的概念⚡&#xff08;2&#xff09;线程库初识 &#x1f33b;2.线程的优点&#x1f33b;3.线程的缺点&#x1f33b;4.线程异常&…...

Flink--9、双流联结(窗口联结、间隔联结)

星光下的赶路人star的个人主页 我还有改变的可能性&#xff0c;一想起这点&#xff0c;我就心潮澎湃 文章目录 1、基于时间的合流——双流联结&#xff08;Join&#xff09;1.1 窗口联结&#xff08;Window Join&#xff09;1.2 间隔联结&#xff08;Interval Join&#xff09;…...

家政服务行业做开发微信小程序可以实现什么功能

家政服务行业开发微信小程序可以实现多种功能&#xff0c;从而提升服务品质和效率&#xff0c;下面我们来详细介绍一些可能实现的功能。 一、展示服务信息 家政服务微信小程序可以展示各种服务信息&#xff0c;包括各类家政服务项目、价格、服务流程、服务人员信息等。用户可以…...

20哈希表-三数之和

目录 LeetCode之路——15. 三数之和 分析&#xff1a; 官方题解&#xff1a; LeetCode之路——15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nu…...

JVM 运行时数据区和垃圾收集算法

在 《深入理解 Java 虚拟机》一书中&#xff0c;作者将运行时数据区和垃圾收集算法放在开头章节&#xff0c;说明了这两个知识点是进一步学习 JVM 的基础知识点&#xff0c;相比后续的 垃圾收集器和 JMM&#xff0c;它也更加的简单。 运行时数据区 运行时数据区是《Java 虚拟…...

Java基于SpringBoot的高校招生系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 简介系统设计思路1 数据库设计2 系统整体设计 系统详细设计1系统功能模块2. 管理员功能模块3学生…...

6. Python使用Asyncio开发TCP服务器简单案例

1. 说明 在Python中开发TCP/IP服务器有两种方式&#xff0c;一种使用Socket&#xff0c;需要在py文件中引入对应的socket包&#xff0c;这种方式只能执行单项任务&#xff1b;另一种方式使用Asyncio异步编程&#xff0c;可以一次创建多个服务器执行不同的任务。 2. 接口说明 …...

景联文科技:AI大模型强势赋能,助力自动驾驶迭代升级

我国一直以来都将自动驾驶作为新兴产业发展的重点领域之一&#xff0c;工信部等相关部委出台了一系列自动驾驶发展战略、规划和标准&#xff0c;一些地方政府也在积极开展关于自动驾驶的地方立法&#xff0c;为自动驾驶技术的研发和应用提供更加具体的法律保障。例如&#xff0…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...