Activity的异常触发情况
1 没有设置横竖屏状态
在 AndroidMainfest.xml
中没有对Activity设置横竖屏状态和 configChanges
时,进行横竖屏切换会导致Activity的异常重新执行生命周期,但与正常的生命周期有所不同:
在Activity异常销毁时,仍旧会执行 onPause()->onStop()->onDestroy()
,但在此之前会回调 onSaveInstanceState()
通过 Bundle
保存Activity状态,在重新创建Activity时会系统会调用 onRestroeInstanceState()
将保存的 Bundle
作为参数同时传递给 onRestoreInstanceState()
和 onCreate()
。只有在Activity异常终止时才会回调 onSaveInstanceSate()
,正常情况下不会回调;
onSaveInstanceState()
这个方法会在 onStop()
之前执行,但可能在 onPause()
之前或之后执行。onRestoreInstanceState()
这个方法会在 onStart()
之后执行。
在Activity异常终止重新创建后,可以通过 onCreate()
或 onRestoreInstanceState()
判断Activity是否被重建了,如果被重建,就可以取出之前保存的数据并恢复。
在Activity异常终止时,系统会为我们做一定的恢复工作:
关于保存和恢复View层次结构,首先Activity被意外终止时,Activity会调用 onSaveInstanceState()
去保存数据,然后Activity委托Window去数据,接着Window再委托它上面的顶级容器去保存数据,顶层容器是一个ViewGroup,一般来说它很可能是DecorView。最后顶层容器再去一一通知它的子元素来保存数据,这样整个数据保存过程就完成了。
在Activity异常终止时,我们知道 onSaveInstanceState()
会将数据保存为Bundle,而Activity重建时 onCreate()
和 onRestoreInstanceState()
都会收到Bundle,哪么有什么不同呢?不同在于,onCreate()
中的Bundle有可能为null因为有可能是正常启动的生命周期,而 onRestoreInstanceStaet()
中的Bundle是一定有值的,因为在异常情况下该方法才会被调用。
2 资源内存不足导致低优先级的Activity被杀死
这种情况的数据存储和恢复过程和第一种情况完全一致。这里描述一下Activity的优先级,从高到低如下:
-
前台Activity:正在和用户交互的Activity,优先级最高
-
可见但非前台Activity:比如Activity中弹出了一个对话框,导致Activity可见但位于后台无法和用户直接交互
-
后台Activity:已经被暂停的Activity,执行了
onStop()
,优先级最低
在内存不足时,系统会根据优先级从低到高杀死Activity所在进程,并后续通过 onSaveInstanceState()
和 onRestoreInstanceState()
来存储和恢复数据。如果一个进程没有四大组件在执行,那么这个进程很容易被系统杀死。防止进程杀死的方法比较好的是后台工作放入Service中从而保证进程有一定优先级。
3 让Activity不产生异常生命周期的解决方案
在 AndroidManifest.xml
中为Activity添加 configChanges
属性:configChanges=”orientation|keyboardHidden”
。
当设置了该属性后,在Activity横竖屏切换时,不会重建Activity,而是会回调 onConfigurationChanged()
。