一、前言
一直以来,自认为Activity的生命周期很简单,确实也很简单,不过,当加入了onSaveInstanceState和onRestoreInstanceState之后,以及手机处于不同的状态时会调用哪些方法,大家真的很清楚了么?比如:竖屏进入应用,此时用户旋转屏幕,然后用户再按电源键(或放置一会让屏幕熄灭),再点亮时,会调用哪些方法?
本篇会采用图文并茂的方式,讲述手机常见的一些状态,以及相互组合的情况,上面的问题就是一个组合情况:旋转+屏幕熄灭+点亮。
二、Activity Lifecycle
按照习惯,先上一张官方文档中的Activity生命周期图。
简单的说一下图中的几个方法:
1. onCreate:Activity第一次启动时会调用此方法,这个方法相比其它方法,耗时最长(onCreate中需要布局:measure, layout, draw等,涉及到整个viewtree);
2. onStart:此时Activity已经可见,但不处于前台(foreground),因此用户还不能操作;
3. onResume:此时Activity不但可见,还可以让用户交互;
------ 至此,Activity已经完全运行,用户可以操作。
4. onPause:此时Activity不出处前台,用户不能操作;
------ 针对第4点,有几种情况,我们需要掌握:
a. 手机长时间待机或用户按了电源键,手机进入熄屏状态,此时Activity不可见,但会进入onPause状态;
b. 弹出一个Dialog,档住Activity,此时Activity部分可见,也进入onPause状态;
5. onStop:此时Activity进入后台,完全不可见;
------ 针对第5点,有几种情况,我们需要掌握:
a. 用户点击Home键,此时Activity进入后台;
b. 用户长按Home键,选择一个曾经使用过的应用,此时手机进入新的应用,因此Activity进入后台;
c. 启动新的Activity,当前Activity进入后台;
6. onDestroy:此时Activity销毁,释放所有资源;
------ 针对第6点,有几种情况,我们需要掌握:
a. 用户按了Back键;
b. 屏幕旋转时,会先销毁,后重新创建Activity;
7. onRestart:此时,Activity将从后台切换回至前台(只有到了onResume才算是真正的到了前台)
------这个与onStop相对应,Activity未onDestroy,只停留在onStop。
三、简单上图分析几个流程
3.1 正常启动
3.2 启动之后点击Home键
3.3 启动之后熄屏(超时熄屏或按电源键)
3.4 启动之后旋转幕屏
3.5 启动、旋转,熄屏再点亮
3.6 Activity跳转并返回
图中已经说的很清楚了,无需我在多说明,不过,3.6中,需要注意一点:
ActivityA跳到ActivityB时,ActivityA先进入onPause状态,等待ActivityB进入onResume即完全可见可交互之后,ActivityA再进入onStop状态。
四、onSaveInstanceState 与 onRestoreInstanceState
这两个方法是不属于生命周期中一定会调用到的方法,onSaveInstanceState用来保存数据,但不是每次都会调用,同样onRestoreInstanceState用来恢复数据,也不是每次都会被调用到,且它们俩并一定非要成对出现才行。
官方文档:
Part1.
Note that it is important to save persistent data in onPause() instead of onSaveInstanceState(Bundle) because the latter is not part of the lifecycle callbacks, so will not be called in every situation as described in its documentation. |
注意:用onPause来替代onSaveInstanceState来保存持久化数据很重要,因为,onSaveInstanceState不是Activity生命周期中回调的一部分,因此,onSaveInstanceState不会每次都被调用。 |
Part2.
Be aware that these semantics will change slightly between applications targeting platforms starting with HONEYCOMB vs. those targeting prior platforms. Starting with Honeycomb, an application is not in the killable state until its onStop() has returned. This impacts when onSaveInstanceState(Bundle) may be called (it may be safely called after onPause() and allows and application to safely wait until onStop() to save persistent state. |
注意:目标平台从Honeycomb开始,与之前的目标平台相比,有些地方有稍微的变化。从Honeycomb开始,生命周期中的方法,直到onStop返回之后,应用才处于“可杀”状态。这也就暗示着当onSaveInstanceState被调用时(再onPause之后调用会更加安全),允许应用更加安全的保持持久化数据,直到生命周期进入onStop。 |
Part3.
Called to retrieve per-instance state from an activity before being killed so that the state can be restored in onCreate(Bundle) or onRestoreInstanceState(Bundle) (the Bundle populated by this method will be passed to both). This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state. For example, if activity B is launched in front of activity A, and at some point activity A is killed to reclaim resources, activity A will have a chance to save the current state of its user interface via this method so that when the user returns to activity A, the state of the user interface can be restored via onCreate(Bundle) or onRestoreInstanceState(Bundle). Do not confuse this method with activity lifecycle callbacks such as onPause(), which is always called when an activity is being placed in the background or on its way to destruction, or onStop() which is called before destruction. One example of when onPause() and onStop() is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState(Bundle) on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause() is called and not onSaveInstanceState(Bundle) is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState(Bundle) on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact. The default implementation takes care of most of the UI per-instance state for you by calling onSaveInstanceState() on each view in the hierarchy that has an id, and by saving the id of the currently focused view (all of which is restored by the default implementation of onRestoreInstanceState(Bundle)). If you override this method to save additional information not captured by each individual view, you will likely want to call through to the default implementation, otherwise be prepared to save all of the state of each view yourself. If called, this method will occur before onStop(). There are no guarantees about whether it will occur before or after onPause(). |
Activity将要被kill之前,将会调用onSaveInstanceState来保存数据,因此,当下一次处于onCreate或onRestoreInstanceState时,可以恢复上一次的数据(Bundle通常都会被传递给这两个方法)。 Activity被杀之前,调用onSaveInstanceState用来恢复这些状态。例如:ActivityB加载起来,ActivityA转为后台不可见,某个时刻系统需要回收资源而干掉了ActivityA,此时,ActivityA就通够通过onSaveInstanceState方法来保存数据,当用户再次返回到ActivityA时,可以通过onCreate或onRestoreInstanceState来恢复数据。 别把onSaveInstanceState与Activity的生命周期回调方法,例如onPause弄混淆!当Activity将要变为后台,或者销毁时,onPause总是会被调用。一个只调用onPause和onStop,并不调用onSaveInstanceState的例子就是用户导航(按返回键)从ActivityB返回ActivityA时,系统不需要去调用ActivityB的onSaveInstanceState方法。另一个例子只调用onPause而不调用onSaveInstanceState是当ActivityB正在它的生命周期中而ActivityA没有被杀掉时。(注:从3.6的图中看出,A跳到B,系统确实调用了A的onSaveInstanceState方法,不过,官方文档这里写出了不一定调用,那么大家还是记住了!) 默认的实现是大多数情况下调用了每个子view控件的onSaveInstanceState方法,以及保存当前有焦点的View(所有的恢复也由默认的onRestoreInstanceState来实现)。如果你需要重写这个方法来保存额外的数据,你可能想调用默认的方法来实现,另外保存它们的所有状态。 如果onSaveInstanceState被调用,该方法会被在onStop之前调用。因此,你不需要关心onSaveInstanceState是在onPause前还是后调用。 |
总之:
1. onSaveInstanceState不属于Activity生命周期里必调的方法,同理onRestoreInstanceState方法;
2. onSaveInstanceState若调用,肯定会在onStop之前,在onPause前后都有可能(虽然我图中都是发生在onPause之前,但应该遵循官方文档,因为不一样的系统,可能顺序不一样);
3. onRestoreInstanceState若调用,肯定会发生在onStart之后,在onPostCreate之前;
注:官方文档有讲过,恢复时,bundle会传递给onCreate和onRestoreInstanceState,之所以有时候用onRestoreInstanceState,是因为此时所有的初始化已经完成。
这里还有个onPostCreate,文档中不建议继承,即便继承了,也需要调用super,否则会异常。这个方法的作用是系统子类做最终的初始化完成。
五、总结
写到这,也差不多该写完了,若有写错的,或是写的不完全的,还请大家指出纠正,本篇中,有讲到一些情况会导致不同的生命周期方法被调用,大家使用时,多留心注意下就没什么问题了。