异常情况下Activity生命周期分析
Activity除了受用户操作所导致的正常生命周期方法调度,还有一些异常情况。比如当前资源相关的系统配置发生改变以及系统的内存不足,Activity就可能被杀死。
1,资源相关的系统配置发生改变导致Activity被杀死并重新创建
简单来说,当我们把一张图片放到drawable目录后,我们就可以根据Resource去获取这张图片。同时为了兼容不同的设备,我们可能还需要在其他一些这样的目录放置不同的图片,比如drawable-mdpi等。这样程序启动时,系统就会根据当前设备情况加载合适的Resource资源,比如手机横屏和竖屏我们会拿到不同的两个图片,比如我们手机当前是竖屏,我们突然旋转屏幕,由于系统配置发生改变,默认情况下,Activity就会销毁并且重新创建。当然我们也可以阻止系统为我们重新创建(启动模式)。生命周期如下。
当系统配置发生改变后,Activity会被销毁,其onPause、onStop、onDestroy都会被调用,同时Activity是异常情况下被终止的,系统会调用onSaveInstanceState来保存当前Activity的状态。方法调用的时机是在onStop之前,他和onPause没有既定的时序关系,可能在onPause之前调用,也可能在之后调用。
需要强调一点,这个方法只有在Activity异常终止时才会调用,正常情况下不会调用。在Activity被异常销毁再重新创建后系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象作为参数传递给onRestoreInstanceState和onCreate。因此我们也可以通过这两个方法来判断Activity是否被重建了,如果被重建了,那么我们可以取出之前保存的数据并恢复,从时序上来说,onRestoreInstanceState在onStart之后。
同时,我们要知道,在onSaveInstanceState和onRestoreInstanceState方法中系统自动为了我们做了一定的恢复工作,具体每个空间系统做了哪些工作,可以查看对应View的onSaveInstanceState方法的源码。
下面代码是我们自己在onSaveInstanceState方法中保存数据,和在onRestoreInstanceState取得保存的数据,我们也可以在onCreate 中恢复,但是在onCreate 需要判断Bundle是否为null,因为Activity正常启动的话Bundle的值是null所以需要额外判断,这两个方法我们都可以用,但是官方更推荐onRestoreInstanceState去恢复。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("extra_text","test");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String test= savedInstanceState.getString("extra_text");
}
2,资源不足导致低优先级的Activity被杀死
这种情况下我们不太好模拟,但是其数据和保存和恢复过程和情况和 1 完全一致,Activity按照优先级从高到底,可以分为以下三种。
(1)前台Activity:正在和用户交互的Activity 优先级最高。
(2)可见但非前台Activity:比如Activity中弹了一个Dialog,导致Activity可见,但是无法交互。
(3)后台Activity:已经被暂停的Activity,优先级最低。
当系统内存不足时,系统会根据上面优先级去杀死目标Activity 所在的进程。并在后续通过 onSaveInstanceState和onRestoreInstanceState来储存和恢复数据。如果一个进程中没有四大组件在执行,那么这个进程将很容易被系统杀死。
根据上面我们知道当系统配置发生变化后,Activity会被重建,那么有没有办法不重新创建呢?
其实如果我们不想系统创建新的Activity可以在AndroidManifest.XML中给对应的Activity指定configChanges 属性,比如不想让Activity在屏幕旋转的时候重新创建。就可以给configChanges属性添加orientation这个值,可以配置的属性如下
表格上项目很多,实际上我常用的只有orientation、locale、keyboardHidden 三项,其他很少用。这样Activity不会重新创建也就不会调用onSaveInstanceState和onRestoreInstanceState 方法,取而代之的是系统调用了Activity的onConfigurationChanged方法,这时候我就可以自己做些特殊处理了。