savedInstanceState吐血详解

Activity的生命周期里并没有提到onSaveInstanceState的触发,这个函数提供了为我们在某些情况下保存Activity信息的机会,但需要注意的是这个函数不是什么时候都会被调用的,官方文档解释的比较清楚,特此
翻译一下。

在activity被杀掉之前调用保存每个实例的状态,以保证该状态可以在onCreate(Bundle)或者 onRestoreInstanceState(Bundle) (传入的Bundle参数是由onSaveInstanceState封装好的)中恢复。这个方法在一个activity被杀死前调用,当该 activity在将来某个时刻回来时可以恢复其先前状态。例如,如果activity B启用后位于activity A的前端,在某个时刻activity A因为系统回收资源的问题要被杀掉,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的例子是当activity B启动并处在activity A的前端:如果在B的整个生命周期里A的用户界面状态都没有被破坏的话,系统是不会调用activity A的onSaveInstanceState(Bundle)的。



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

很多不明白Activity类中包含的onSaveInstanceState和onRestoreInstanceState有什么用,首先声 明下使用这两个方法时一定要注意情况和了解Activity的生命周期,否则有的时候 onSaveInstanceState和onRestoreInstanceState 可能不会被触发,虽然他们都是Activity的重写方法。(文/Android开发网)

他们比较常用到的地方是 Sensor、Land和Port布局的自动切换,过去Android开发网曾经说过解决横屏和竖屏切换带来的数据被置空或者说onCreate被重复调 用问题,其实Android提供的onSaveInstanceState方法可以保存当前的窗口状态在即将布局切换前或当前Activity被推入历史 栈,其实布局切换也调用过onPause所以被推入Activity的history stack,如果我们的Activity在后台没有因为运行内存吃紧被清理,则切换回时会触发onRestoreInstanceState方法。

这两个方法中参数均为Bundle,可以存放类似 SharedPreferences 的数据,所以使用它们作为当前窗口的状态保存是比较合适的。实际使用代码

从这句话可以知道,当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
注意上面的双引号,何为“容易”?言下之意就是该activity还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?通过重写一个 activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我 们可以清楚地知道当某个activity(假定为activity A)显示在当前task的最上层时,其onSaveInstanceState方法会在什么时候被执行,有这么几种情况:

1、当用户按下HOME键时。这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则

2、长按HOME键,选择运行其他的程序时。

3、按下电源按键(关闭屏幕显示)时。

4、从activity A中启动一个新的activity时。

5、屏幕方向切换时,例如从竖屏切换到横屏时。在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行

总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则 onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。

开启应用—>>back键一下(此时回到手机主界面,但是还在任务栏中)–>>点击任务栏中的程序
11-27 15:40:19.245: I/hhhd(28366): onCreate
11-27 15:40:19.268: I/hhhd(28366): onStart
11-27 15:40:19.268: I/hhhd(28366): onResume

11-27 15:40:20.674: I/hhhd(28366): onPause
11-27 15:40:21.142: I/hhhd(28366): onStop
11-27 15:40:21.143: I/hhhd(28366): onDestroy

11-27 15:40:22.902: I/hhhd(28366): onCreate
11-27 15:40:22.931: I/hhhd(28366): onStart
11-27 15:40:22.931: I/hhhd(28366): onResume

开启应用—>>home键一下(此时回到手机主界面,但程序还在任务栏中)—>>点击任务栏中的程序
11-27 15:58:30.204: I/hhhd(29984): onCreate
11-27 15:58:30.232: I/hhhd(29984): onStart
11-27 15:58:30.233: I/hhhd(29984): onResume

11-27 15:58:33.667: I/hhhd(29984): onPause
11-27 15:58:34.192: I/hhhd(29984): onSaveInstanceState
11-27 15:58:34.192: I/hhhd(29984): onStop

11-27 15:58:37.466: I/hhhd(29984): onStart
11-27 15:58:37.467: I/hhhd(29984): onResume

只要Activity不finish,Activity进入后台(比如Home键,跳转到其他的Activity),则其就会调用onSaveInstanceState(Bundle outState)方法,
而且这个方法是在onPause方法和onStop之间进行调用的。

如果Activity是执行了finish方法(相当于点击了回退键),才进入的后台,则不调用这个onSaveInstanceState(Bundle outState),
而且下次再进入时,也不会使用这个保存的数据。

当切换横竖屏幕
11-27 16:44:54.464: I/hhhd(2080): onPause
11-27 16:44:54.464: I/hhhd(2080): onSaveInstanceState
11-27 16:44:54.465: I/hhhd(2080): onStop
11-27 16:44:54.465: I/hhhd(2080): onDestroy
11-27 16:44:54.555: I/hhhd(2080): onCreate
11-27 16:44:54.594: I/hhhd(2080): —>>dfsdaf //保存在savedInstanceState的数据
11-27 16:44:54.602: I/hhhd(2080): onStart
11-27 16:44:54.602: I/hhhd(2080): onRestoreInstanceState
11-27 16:44:54.615: I/hhhd(2080): onResume

当锁定屏幕:
11-27 16:47:25.910: I/hhhd(2502): onPause
11-27 16:47:25.919: I/hhhd(2502): onSaveInstanceState
11-27 16:47:25.919: I/hhhd(2502): onStop

当解锁屏幕:
11-27 16:48:26.956: I/hhhd(2782): onStart
11-27 16:48:26.959: I/hhhd(2782): onResume

当来电时:
11-27 08:59:30.194: I/hhhd(1784): onPause
11-27 08:59:30.894: I/hhhd(1784): onSaveInstanceState
11-27 08:59:30.894: I/hhhd(1784): onStop

我们都知道Activity是存在栈中的,实行后进先出的原则,那么当一个新的Activity B 覆盖在Activity A之上时候,A就会调用onSaveInstanceState方法保存A里面UI的状态,当然,你也可以添加一个自定义需要保存的东西放在bundle中,当发生一些事件(比如 切换屏幕 ,)会从onCreate中把bundle里面的UI状态或者上面保存的东西提取出来

你可能感兴趣的:(savedInstanceState吐血详解)