Android学习:onSaveInstanceState (Bundle outState)方法简介

目录

PART 1:方法在何时调用

首先看下官方文档的解释:

PART 2:使用案例

PART 3:onPause()和onSaveInstanceState()区别

不是可以在 onPause() 中保存数据吗?为什么又搞出这样一个家伙来?它们之间是什么关系呢?


PART 1:方法在何时调用

首先看下官方文档的解释:

在 Activity 被销毁之前被调用来保存每个实例的状态,这样就可以保证该状态能够从 onCreate(Bundle) 或者onRestoreInstanceState(Bundle)恢复过来。

本方法在 Activity 可能被销毁前调用,这样当该 Activity 在将来某个时刻重新回来时可以恢复其之前的状态。例如,如果 Activity B 启用后位于 Activity A 的前端,在某个时刻 Activity A 因为系统回收资源的原因要被销毁,Activity A 有机会通过 onSaveInstanceState() 来保存其用户界面状态,使得将来用户返回到 Activity A 的时候能够通过 onCreate(Bundle) 或者onRestoreInstanceState(Bundle) 来恢复其界面状态。

不要将这个方法和 Activity 生命周期中的回调如 onPause() 或 onStop() 搞混淆了,onPause() 在 Activtiy 被放置到后台或者自行销毁时总会被调用,onStop() 在 Activity 被销毁时被调用。一个会调用 onPause() 和 onStop() 但不会触发 onSaveInstanceState() 的例子是当用户从 Activity B 返回到 Activity A 时:没有必要调用 B 的 onSaveInstanceState(Bundle)方法,因为此时的 B 实例永远不会被恢复,因此系统会避免调用它。一个调用 onPause() 但不调用 onSaveInstanceState(Bundle) 方法的例子是当 Activity B 启动后处在 Activity A 的前端:如果在B的整个生命周期里 A 的用户界面状态都没有被破坏的话,系统是不会调用 Activity A 的onSaveInstanceState(Bundle)方法。

默认的实现负责了大部分 UI 实例状态的保存,采用的方式是调用 UI 层上每个拥有 id 的 view 的 onSaveInstanceState()方法 ,并且保存当前获得焦点的 view 的 id (所有保存的状态信息都会在默认的 onRestoreInstanceState(Bundle) 实现中恢复)。如果你覆写这个方法来保存额外的没有被各个view保存的信息,你可能想要在默认实现过程中调用或者自己保存每个视图的所有状态。

如果被调用,这个方法会在 onStop() 前被触发,但系统并不保证是否在 onPause() 之前或者之后触发。

PART 2:使用案例

Activity 中的 onSaveInstanceState() 方法和 onRestoreInstanceState() 方法并不是生命周期方法,它们不同于 onCreate()、onPause() 等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键),由系统销毁一个 Activity 时,onSaveInstanceState() 方法就会被调用。但是当用户主动去销毁一个 Activity 时,例如在应用中按返回键,onSaveInstanceState() 方法就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState() 方法只适合用于保存一些临时性的状态,而onPause() 方法适合用于数据的持久化保存。

另外,当屏幕的方向发生了改变, Activity 会被销毁并重新创建,如果你想在 Activity 被销毁前缓存一些数据,并且在 Activity 被重新创建后恢复缓存的数据。可以重写 Activity 中的 onSaveInstanceState() 方法和 onRestoreInstanceState()方法,如下: 

public class PreferencesActivity extends Activity {
    
    private String name;
 
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        // 重新创建后恢复缓存的数据
        name = savedInstanceState.getString("name");
        super.onRestoreInstanceState(savedInstanceState);
    }
 
    protected void onSaveInstanceState(Bundle outState) {
        // 被销毁前缓存一些数据
        outState.putString("name", "l_yqing");
        super.onSaveInstanceState(outState);
    }
}


PART 3:onPause()和onSaveInstanceState()区别

当用户启动一个新 Activity 之后,之前的 Activity 可能在内存中处于停止状态也可能由于新 Activity 需要更多内存而被系统销毁了,但不论怎样,当用户在新 Activity 上点击返回键时,他希望看到的是原先的 Activity 的界面。原先的 Activity 如果是被重新创建的,那么它就要恢复到用户最后看到它时的样子,我们该怎么做呢?其实也不难,在 onPause() 、onStop() 或 onDestroy() 中保存必要的数据就行了。但是现在Google又冒出一个新的东西:onSaveInstanceState(),观其名可知其意:它是专门用来保存实例状态的,这个“实例”不是指的 Activity 对象,而是它所在的进程,因为Activity 的销毁是因为它所在的进程被杀掉而造成的。onSaveInstanceState()是在系统感觉需要销毁Activity时调用的,它被传入一个参数Bundle,这个Bundle可以被认为是个 Map 字典之类的东西,用“键-值”的形式来保存数据。

不是可以在 onPause() 中保存数据吗?为什么又搞出这样一个家伙来?它们之间是什么关系呢?


原来,onSaveInstanceState() 方法的主要目的是保存和 Activity 的状态有关的数据,当系统在销毁 Activity 时,如果它希望 Activity 下次出现的样子跟之前完全一样,那么它就会调用onSaveInstanceState(),否则就不调用。所以要明白这一点:onSaveInstanceState() 方法并不是永远都会调用。比如,当用户在一个 Activity 点击返回键时,就不会调用,因为用户此时明确知道这个 Activity 是要被销毁的,并不期望下次它的样子跟现在一样(当然开发者可以使它保持临死时的表情,你非要这样做,系统也没办法),所以就不用调用onSaveInstanceState()。现在应该明白了:在onPause()、onStop() 以及 onDestroy() 中需要保存的是那些需要永久化的数据,而不是保存用于恢复状态的数据,状态数据有专门的方法:onSaveInstanceState()。数据保存在一个 Bundle 中,Bundle 被系统永久化。当再调用 Activity 的onCreate()时,原先保存的 Bundle就被传入,以恢复上一次临死时的模样,如果上次被销毁时没有保存 Bundle,则为 null。

还没完呢,如果你没有实现自己的 onSaveInstanceState(),但是 Activity 上控件的样子可能依然能被保存并恢复。原来 Activity 类已实现了onSaveInstanceState(),在 onSaveInstanceState() 的默认实现中,会调用所有控件的相关方法,把控件们的状态都保存下来,比如 EditText 中输入的文字、CheckBox 是否被选中等等。然而不是所有的控件都能被保存,这取决于你是否在 layout 文件中为控件赋了一个名字(android:id)。有名的就存,无名的不管。

既然有现成的可用,那么我们到底还要不要自己实现 onSaveInstanceState() 方法呢?这就得看情况了,如果你自己的派生类中有变量影响到UI,或你程序的行为,当然就要把这个变量也保存了,那么就需要自己实现,否则就不需要,但大多数情况肯定需要自己实现一下下了。对了,别忘了在你的实现中调用父类的 onSaveInstanceState() 方法。


注:由于 onSaveInstanceState() 方法并不是在每次被销毁时都会调用,所以不要在其中保存那些需要永久化的数据,执行保存那些数据的最好地方是在 onPause() 方法中。
————————————————
版权声明:本文为CSDN博主「L_YQing」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
https://blog.csdn.net/l_yqing/article/details/7814918/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340