1.activity的启动过程:
启动activity的请求由instrumentation处理,通过binder向AMS发起请求,AMS内部维护着一个ActivityStack,负责同步Activity的状态,AMS通过ActivityThread去同步Activity的状态从而完成生命周期方法的调用。
2.异常情况下Activity的生命周期分析:
(1)资源相关的系统配置发生改变导致Activity被杀死并重新创建(横竖屏切换):
Activity会被销毁,系统会调用onSaveInstanceState来保存当前Activity的状态,该方法在onStop前调用,与onPause没有固定的时序关系,且只有在Activity被异常终止的情况下才会被调用。Activity被重新创建后,系统调用onRestoreInstanceState,把onSaveInstanceState方法保存的Bundle对象作为参数传给onRestoreInstanceState和onCreate。采用onRestoreInstanceState恢复数据而不是用onCreate中的参数Bundle saveninstanceState恢复是因为onRestoreInstanceState如果被调用,则Bundle类型的参数必定不为null不需要再做判断,而在正常启动的情况下onCreate中Bundle类型参数为空。
(2)资源内存不足导致低优先级的Activity被杀死:
1).Activity优先级排序:
前台activity(正在与用户交互的activity) > 可见但非前台activity(弹出对话框等原因导致该activity部分可见但并不处于前台) > 后台activity(已经被暂停的activity)
如果系统内存不足,就会按照该优先级杀死目标activity所在进程,之后通过onSaveInstanceState和onRestoreInstanceState保存和恢复数据。
2).当系统配置发生变化时限制activity重新创建:
在AndroidManifest中设置activity的
configChanges属性,常用属性
orientation、
screenSize、
keyboardHidden。
总结:当屏幕翻转时系统内部发生的变化:若没有设置activity的configChanges为"orientation|screenSize",翻转屏幕activity会被销毁,在执行onStop前调用onSaveInstanceState保存当前状态,然后重新创建,调用onRestoreInstanceState恢复状态,
如果设置了configChanges 则会调用onConfigurationChanged方法。
3.启动模式
(1)standard:
每次启动activity都会创建一个新的实例。这种模式下,谁启动了这个activity,那么新的activity就会在启动它的activity所在的栈中。如果用ApplicationContext去启动standard模式的Activity会报错,因为新activity会默认进入启动它的activity的栈中,而非activity类的Context并没有任务栈。解决方法:为待启动的activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动时会为它创建一个新的任务栈,实际上是以singleTask模式启动。
(2)singleTop栈顶复用模式:
如果新activity已位于任务栈栈顶,那么不会被重新创建,会调用它的onNewIntent方法,但是该activity的onCreate,onStart不会被调用。如果新activity存在但不位于栈顶,则仍会创建新的实例。
(3)singleTask栈内复用模式:
只要activity在一个栈内存在,都不会创建实例,会调用onNewIntent方法。当一个singleTask模式的activity A启动后,系统首先会寻找是否有A想要的任务栈,如果不存在,则创建新的任务栈,然后把创建A的实例放入栈中。如果存在A所需的任务栈,则看栈中是否有A的
实例,如果有实例,则把A调到栈顶(
在A之上的Activtiy全部出栈)并调用他的onNewIntent方法,如果不存在实例,则创建实例并压入栈中。
(4)singleInstance单实例模式:
为该模式的activity单独创建一个新的任务栈,而且
后续的请求都不会创建新的activity实例,除非这个单独的任务栈被系统销毁了。
查看任务栈信息指令:dumpsys activity
如果有两个任务栈,前台任务栈为AB,后台任务栈为CD(启动模式均为singleTask),如果请求启动D,则整个后台任务栈会被切换到前台,后退列表变成ABCD。
如果请求启动C 则后退列表变为ABC。因为调用启动模式为singleTask 的C会让栈内Activity D出栈。
TaskAffinity:标识Activity所需要的任务栈名字,默认情况下所有Activity的所需任务栈名字为应用的包名,一般和singleTask配合使用。
如果Activity A(standard)启动Activity B(launchMode:singleTask,taskAffinity:task1),B再启动Activity C(launchMode:singleTask,taskAffinity:task1),C再启动A,A再启动B,此时按两次Back,将会返回桌面。
分析:1.A启动B,系统会创建名为task1的任务栈并创建B的实例将B入栈。
2.B启动C,由于task1存在所以系统只创建C的实例并将C入栈。
3.C再启动A,由于A是standard所以会创建A的实例,并加入启动它的Activity所在的任务栈,即task1.
4.此时系统内存在两个任务栈:(1)默认包名任务栈,内部为A(2)task1任务栈,内部为BCA。
5.再由A启动B,由于存在task1并且task1内有Activity B,所以系统不会创建B的实例而是将B上放的CA全部出栈,此时task1内部只剩Activity B。
6.第一次按back B出栈,task1任务栈销毁,位于前台的是默认任务栈的A,第二次按back,A出栈,返回桌面。
常用的Flags:(intent.setFlags优先级比AndroidManifest中setLaunchMode更高)
1.FLAG_ACTIVITY_NEW_TASK:效果与在XML中指定“singleTask”启动模式相同。
2.FLAG_ACTIVITY_SINGLE_TOP:效果与在XML中制定“singleTop”启动模式相同。
3.FLAG_ACTIVITY_CLEAR_TOP:同一任务栈位于该Activity上方的Activity都要出栈
4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:效果与在XML中设定android:excludeFromRecents = “true” 相同,具有该标记的Activity不会出现在历史Activity的列表中。