1. Activity生命周期分析
这里生命周期分为两部分内容:
- 一是典型情况下的生命周期
指在有用户参与的情况下,Activity所经过的生命周期的改变 - 另一部分是异常情况下的生命周期
Activity被系统回收或由于当前设备的Configuration发生改变从而导致Activity被销毁重建,与典型情况下的关注点略有不同。
1.1 典型情况下的生命周期
正常情况下会经过如下生命周期:
onCreate
:表示Activity正在被创建,做一些初始化工作,如加载布局,初始化一些数据onRestart
:表示Activity正重新启动。当当前Activity从不可见重新变为可见状态,就会被调用onStart
:表示Activity正在启动,此时Activity已经可见,未在前台,无法交互onResume
:表示Activity已经可见在前台,可交互了onPause
:表示Activity正在停止,可做一些不耗时操作,如停止动画,存储数据。注意
:onPause必须先执行完,新Activity的onResume才会执行onStop
:表示Activity即将停止,不能做太耗时操作。onDestroy
:表示Activity即将销毁,可以做一些回收工作与资源释放
附加情况:
- 用户打开新Activity或者切换到桌面,回调:onPause -> onStop 如果新Activity采用透明主题,当前Activity不会回调onStop
- 用户按back键回退,回调为:onPause -> onStop -> onDestroy
- Activity被系统回收再次打开,生命周期回调一样,但是不代表所有过程一样
- 整个生命周期,onCreate与onDestroy只可能有一次调用
问题一:onStart和onResume,onPause和onStop有什么实质性不同?
这两个配对回调的意义不同,从是否可见,是否在前台,其他基本无差别
问题二:当前Activity为A,新开打B,B的onResume和A的onPause哪个先执行?
这个可以从源码获得解释,在新Activity启动之前,栈顶的Activity需要先onPause后,新的Activiy才能启动
1.2 异常情况下的生命周期
1.2.1 资源相关系统配置发生改变导致Activity被杀死并重新创建
典型例子本来手机屏幕是竖屏状态,突然旋转屏幕,系统配置发生了变化,默认情况下,Activity就会被销毁并且重新创建,当然也可以阻止系统重新创建我们的系统
当系统配置发生改变后,Activity会被销毁,其onPause、onStop、onDestroy均会被调用,系统会调用onSaveInstanceState来保存当前的Activity状态,在onStop之前调用,与onPause无既定时序关系。Activity被重新创建后,系统会调用onRestoreInstanceState,并且把onSaveInstanceState保存的Bundle对象作为参数同时传递给onRestoreInstanceState和onCreate方法。onRestoreInstanceState调用时机在onStart之后
系统自动为我们做了一定的恢复工作,系统默认为我们保存当前Activity的视图结构,如文本框中输入数据,ListView滚动位置等,具体针对哪个View系统能为我们恢复哪些数据,可以查看View的源码。
在onSaveInstanceState中存储一个字符串,Activity销毁重建可以在onCreate或onRestoreInstanceState中接收,二者区别是onCreate需要判空而后者不需要,onRestoreInstanceState被调用则一定有值
Activity正常销毁时,系统不会调用onSaveInstanceState。
1.2.2 资源内存不足导致低优先级的Activity被杀死
优先级从高到低分为三种:
- 前台Activity:正在和用户交互,优先级最高
- 可见非前台Activity:
- 后台Activity:优先级最低
内存不足,按照上述优先级去杀死目标Activity所在进程,后续通过onSaveInstanceState和onRestoreInstanceState存储和恢复数据。一个进程如果没有四大组件在执行,很容易被系统杀死。较好方法是将后台工作放入Service中从而保证进程有一定的优先级。
1.2.3 系统异常销毁Activity不想重建
系统配置发生改变,如果不想系统重新创建Activity,可以给Activity指定configChange属性。
示例:如果不想Activity在屏幕旋转时重新创建就可以给configChanges属性添加orientation这个值。
android:configChanges="orientation"
如果想要指定多个值,可以用“|”连接起来。一般常用的只有local,orientation和keyboardHidden这三个选项,其他很少使用
2. Activity启动模式
2.2.1 Activity的LaunchMode
目前有四种启动模式:standard、singleTop、singleTask和SingleInstance
standard
:标准模式,系统默认模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。当用ApplicationContext去启动standard模式的Activity,会报错,因为非Activity类型的Context没有所谓的栈,解决方法是将待启动Activity指定为FLAG_ACTIVITY_NEW_TASK标记位。singleTop
:栈顶复用模式。新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。singleTask
:栈内复用模式。这是一种单实例模式。只要Activity在一个栈中存在,多次启动此Activity都不会重新创建实例,并把这个活动之上的所有活动统统出栈。如原来栈是ABC,现在启动B,则栈为BC。singleInstance
:单实例模式。具有此模式的Activity只能单独地位于一个任务栈中。
对于一个具有singleTask模式的Activity请求启动后,系统首先会寻找是否存在A想要的任务栈。那么什么是Activity所需要的任务栈?需要从一个参数说起:TaskAffinity。这个参数标识了一个Activity所需要的任务栈的名字。默认所有Activity所需的任务栈名字为应用的包名,也可以为每个Activity都单独指定TaskAffinity属性,这个属性必须不能和包名相同。TaskAffinity主要和singleTask启动模式或allowTaskReparenting属性配对使用。
任务栈分为前台任务栈和后台任务栈,用户可以通过切换将后台任务栈再次调到前台。
当TaskAffinity
和allowTaskReparenting
结合时,这种情况比较复杂,会产生特殊
的效果。当一个