Activity_A 打开 Activity_B 时会有哪些生命周期回调
当 Activity_B 的 launchMode 为 Standard 或者 Activity_B 没有可复用的实例时:
A.onPause -> B.onCreate -> B.onStart -> B.onResume
-> A.onStop -> A.onSaveInstanceState
当 Activity_B 的 launchMode 为 SingleTop 且 Activity_B 已经在栈顶时(如点击通知栏、连点):
B.onPause -> B.onNewIntent -> B.onResume
当 Activity_B 的 launchMode 为 SingleInstance 或 SingleTask 且 Activity_B 有可复用的实例时:
A.onPause -> B.onRestart -> B.onStart -> B.onNewIntent -> B.onResume
-> A.onStop -> A.onSaveInstanceState
Dialog 对生命周期的影响
生命周期回调都是 AMS 通过 Binder 通知应用进程调用的,而 Dialog、Toast、PopupWindow 本质上都直接是通过 WindowManager.addView 来显示的(没有经过 AMS),所以不会对生命周期有任何影响
如果是启动一个 Theme 为 Dialog的Activity , 则生命周期为:A.onPause -> B.onCreate -> B.onStart -> B.onResume,注意这边没有前一个 Activity 不会回调 onStop,因为只有在 Activity 切到后台不可见才会回调 onStop
onActivityResult 回调时机
B.onPause -> A.onActivityResult -> A.onRestart -> A.onStart -> A.onResume
onCreate 方法里写死循环会触发 ANR 吗
ANR 的四种场景
- Service TimeOut: Service未在规定时间执行完成
- 普通服务-前台进程 20s,普通服务-后台进程 200s
- 前台服务 10s
- BroadCastQueue TimeOut: 有序广播未在规定时间内未处理完成
- 前台广播 10s
- 后台广播 60s
- ContentProvider TimeOut
- publish 在 10s 内没有完成
- getResolver 20s 未获取成功(返回空,不会触发ANR)
- Input Dispatching timeout
- 5s 内未响应键盘输入、触摸屏幕等事件
我们可以看到,Activity 的生命周期回调的阻塞并不在触发 ANR 的场景里面,所以并不会直接触发 ANR。只不过死循环阻塞了主线程,如果系统再有上述的四种事件发生,就无法在相应的时间内处理从而触发 ANR
onRestart调用场景:
- 按下home键之后,然后切换回来,会调用onRestart()
- 从本Activity跳转到另一个Activity之后,按back键返回原来Activity,会调用onRestart()
- 从本Activity切换到其他的应用,然后再从其他应用切换回来,会调用onRestart()
Activity任务栈
Task是一个具有栈结构的对象,一个Task可以管理多个Activity。Activity一共有四种launchMode:Standard、SingleTop、SingleTask、SingleInstance,我们可以在AndroidManifest.xml中通过Android:launchMode属性来配置Activity启动模式
1.Standard
Standard是默认的启动模式,不用为Activity配置android:launchMode属性即可,当然也可以指定为Standard,每次跳转系统都会在Task中生成一个新的Activity实例,并且放于栈结构的顶部
2.SingleTop
我们在上面的基础上为Activity指定属性android:launchMode="SingleTop",系统就会按照SingleTop启动模式处理跳转行为,系统发现Activity实例位于栈顶,则重复利用,调用onNewIntent方法,否则重新生成一个实例
3.SingleTask
当一个应用程序加载一个SingleTask模式的Activity时,首先会检查是否存在与它的taskAffinity相同的Task,如果存在,那么检查是否实例化,如果已经实例化,那么销毁在该Activity以上的Activity(Intent.FLAG_ACTIVITY_CLEAR_TOP销毁目标Activity和它之上的所有Activity,重新创建目标Activity)并调用onNewIntent,如果没有实例化,那么该Activity实例化并入栈,如果不存在,那么就重新创建Task并入栈
4.SingleInstance
SingleInstance模式会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中,并保证不再有其他Activity实例进入
当一个应用程序加载一个SingleInstance模式的Activity时,如果该Activity没有被实例化,那么就重新创建一个Task,并入栈,如果已经被实例化,那么就调用该Activity的onNewIntent,singleInstance的Activity所在的Task不允许存在其他Activity,任何从该Activity加载的其它Activity(假设为Activity2)都会被放入其它的Task中,如果存在与Activity2相同affinity的Task,则在该Task内创建Activity2,如果不存在,则重新生成新的Task并入栈
每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task,如果一个Activity没有显式的指明该Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名,而Task也有自己的affinity属性,它的值等于它的根Activity的taskAffinity
LaunchMode | 应用场景 |
---|---|
standard | 本应用内普通界面(很少自身跳转自身) |
singleTop | 覆盖页面-逻辑不可控时使用-防止需要多次back:推送通知栏 |
singleTask | 应用主页、在线教室 |
singleInstance | 独立页面:来电显示、闹铃提醒(防止回退到自身) |
注意:A -> B -> C -> D -> A -> B,A(Standard)和B(SingleTask)在一个任务栈,C(SingleTask)和D(SingleTask)在一个任务栈,返回时的顺序是B -> A -> A -> D -> C,需要考虑任务栈跳转的情况,优先清退当前任务栈
一开始,创建的Activity都会在创建它的Task中,并且大部分都在这里度过了它的整个生命,然而有一些情况,创建的Activity会被分配其它的Task中去,有的甚至,本来在一个Task中,之后出现了转移。我们首先分析一下android文档给我们介绍的两种情况
第一种情况:如果该Activity的allowTaskReparenting设置为true,当该Activity标记的task(Activity为根Activity)进入后台,当一个和它有相同affinity的Task进入前台时,该task会重新宿主,进入到该前台的task中(activity的launchMode设置为singleInstance则allowTaskReparenting不起作用)
第二种情况:如果加载某个Activity的intent,Flag被设置成FLAG_ACTIVITY_NEW_TASK时,它会首先检查是否存在与自己taskAffinity相同的Task,如果存在,那么它会直接宿主到该Task中,如果不存在则重新创建Task
1.android:allowTaskReparenting
2.android:alwaysRetainTaskState:这个属性用来标记应用的task是否保持原来的状态,“true”表示总是保持,“false”表示不能够保证,默认为“false”。此属性只对task的根Activity起作用,其他的Activity都会被忽略,默认情况下,如果一个应用在后台呆的太久例如30分钟,用户从主选单再次选择该应用时,系统就会对该应用的task进行清理,除了根Activity,其他Activity都会被清除出栈,但是如果在根Activity中设置了此属性之后,用户再次启动应用时,仍然可以看到上一次操作的界面
3.android:clearTaskOnLaunch:这个属性用来标记是否从task清除除根Activity之外的所有的Activity,“true”表示清除,“false”表示不清除,默认为“false”。同样,这个属性也只对根Activity起作用,其他的Activity都会被忽略。allowTaskReparenting转移过来的activity也被清除掉(MA)
4.android:finishOnTaskLaunch:这个属性和android:allowTaskReparenting属性相似,不同之处在于allowTaskReparenting属性是重新宿主到有共同affinity的task中,而finishOnTaskLaunch属性是销毁实例,如果这个属性和android:allowTaskReparenting都设定为“true”,则这个属性胜出
参考文档:
https://developer.android.com/guide/components/activities/tasks-and-back-stack
https://developer.android.com/guide/topics/manifest/activity-element#reparent