学习清单:
- Activity的生命周期
- Activity的启动模式
- IntentFilter的匹配规则
1.1Activity的生命周期全面分析
1.1.1典型情况下的生命周期分析
正常情况下,Activity常用生命周期有以下七种
(1)onCreate:表示Activity正在被创建,生命周期的第一个方法。
(2)onRestart:表示Activity正在重新启动。
(3)onStart:表示Activity正在被启动。
(4)onResume:表示Activity是可见的,出现在前台并且开始活动。
(5)onPause:表示Activity正在停止。
(6)onStop:表示Activity即将停止。
(7)onDestory:表示Activity即将被销毁。
图 1-1
一个Activity生命周期中,有可能出现这几种情况:
(1)Activity第一次启动时,回调有:onCreate -> onStart -> onResume。
(2)用户打开新的Activity或者切换到桌面时:onPause -> onStop。若Activity采用了透明主题,则Activity不会回调onStop。
(3)用户再回到原Activity时:onResume -> onStart -> onResume。
(4)用户按Back键回退时:onPause -> onStop -> onDestroy。
(5)当Activity被系统回收再打开时,生命周期与(1)一样。
(9)onCreate和onDestroy分别标识着Activity的创建和销毁,在整个生命周期中只有一次调用。
onStart和onStop分别标识着Activity的开始和停止,前者Activity可见,后者Avtivity不可见。
onResume和onPause分别标识着Activity的继续和暂停。前者Activity在前台,后者Activity在后台。
1.1.2 异常情况下的生命周期分析
1.资源相关的系统配置发生改变导致Activity被杀死并重新创建
图1-2
举个例子:当前Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity就会被销毁并重新创建,其生命周期如图1-2所示。
分析:当系统配置发生更改后,Activity会被销毁,其onPause、onStop、onDestroy都会被调用,由于Activity是在异常情况下终止的,系统会调用onSaveInstanceState来保存当前Activity的状态(这个方法只会出现在Activity异常终止的情况下,正常情况下不会调用这个方法)。
当Activity被重新创建后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象作为参数传递给onRestoreInstanceState和onCreate方法。因此,可以通过onRestoreInstanceState和onCreate方法来判断Activity是否被重建了,如果被重建了,我们就可以取出之前保存的数据并恢复,从时序上来说,onRestoreInstanceState的调用时机在onStart之后。
2.资源内存不足导致优先级低的Activity被杀死
Activity优先级从高到低可以分为以下三种:
(1)前台Activity ——正在和用户交互的Activity,优先级最高。
(2)可见但并非前台Activity——比如Activity中弹出一个对话框,导致Activity可见,但是位于后台无法和用户交互。
(3)后台Activity——已经被暂停的Activity,比如执行了onStop,优先级最低。
当系统内存不足时,系统就会按照上述优先级去杀死目标Activity所在的进程,并在后续onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。
1.2Activity的启动模式
1.2.1 Activity 的LaunchMode
任务栈:一种“先进后出”的栈结构,存放Activity实例。
四种启动模式
(1)standard:标准模式,也是系统的默认模式,每次启动Activity都会重新创建一个新的实例,不管这个实例是否已经存在。
(2)singleTop:栈顶复用模式,如果新的Activity位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会回调。
(3)singleTask:栈内复用模式。一种单实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和singleTop一样,系统也会回调onNewIntent。
- 比如任务栈S1中有ABC,这个时候Activity D以singleTask模式请求启动,其所需的任务栈为S2,由于S2和D的实例都不存在,系统会先创建任务栈S2,然后再创建D的实例并将其入栈到S2。
- 假设D所需的任务栈为S1,其他情况与上述一样,由于S1存在,所以系统会直接创建D 的实例并将其入栈到S1。
- 如果D所需的任务栈为S1,并且当前任务栈S1的情况为ADBC,此时D不会被创建,系统会把D切换到栈顶并调用其onNewIntent方法,singleTask默认具有clearTop效果,导致栈内所有在D上面的Activity全部出栈,最终S1中的情况为AD。
(4)singleInstance:单实例模式,一种加强的singleTask模式,除了singTask模式的所有特性外,还加强了一点,那就是具有此种模式的Activity只能单独地位于一个任务栈中。
举个启动模式的小例子:假设目前有两个任务栈,前台任务栈情况为AB,而后台任务栈情况为CD,假设CD的启动模式均为singleTask。现在请求启动D,那么整个后台任务都会切换到前台,这个时候按下back键的后退列表为ABCD,如图1-3。如果请求启动D而不是启动C,后退列表为ABC,如图1-4。
图1-3
图1-4
在singleTask启动模式中,多次提到某个Activity所需的任务栈,什么是Activity所需的任务栈?
参数TaskAffinity标识了一个Activity所需要的的任务栈的名字,默认情况下,此参数为应用的包名,可以自己指定,TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。
任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity处于暂停状态。
当TaskAffinity和singleTask启动模式配对使用时,它是具有该模式的Activity的目前任务栈的名字,带启动的Activity会运行在名字和TaskAffinity相同的任务栈中。
当TaskAffinity和allowTaskReparenting结合的时候,当一个应用A启动应用B 的某个Activity后,这个Activity的allowTaskReparenting属性为true的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中。
1.2.2 Activity的Flags
Activity常用的标记位:
-
FLAG_ACTIVITY_NEW_TASK :为Activity指定“singleTask”启动模式。
-
FLAG_ACTIVITY_SINGLE_TOP:为Activity指定“singleTop”启动模式。
-
FLAG_ACTIVITY_CLEAR_TOP:具有此标记位的Activity,当它启动时,在同一任务栈所有位于它上面的Activity都要出栈,此标记一般会与singleTask一起出现。
-
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有此标记的Activity不会出现在历史Activity的列表中,等同
android:excludeFromRecents = "true"
。
1.3IntentFilter的匹配规则
启动Activity分为两种,显示调用和隐式调用。显示调用需要明确指定被启动对象的组件信息,包括包名和类名,而隐式调用则不需要明确指定组件信息。
隐式调用:Intent 能够匹配目标组件中的action、category、data 这三个过滤信息,只有一个Intent能同时匹配这三种过滤信息才算完全匹配。
-
只有一个intent同时匹配 action、category、 data 才算完全匹配,只有 完全匹配 才能启动activity。
-
一个 activity 可以 有多个 intent-filter ,一个 intent 只要成功匹配任意一组intent-filter 就可以启动activity。
A.action的匹配规则
-
action的匹配要求Intent中的action 存在且必须和过滤规则中的其中action 相同。
-
action 是区分大小写的。
B.category的匹配规则
-
ntent中的 category 只要有一个和 匹配规则中的category 相同就可以匹配。
-
intent 不设置 category ,也可以和其匹配,因为系统在调用 startActivity 或者 startActivity ForResult的时候会自动添加 android.intent.category.DEFAULT 这个category。
C.data的匹配规则
-
类似于action。
-
如果过滤规则中有data,那么intent中也必须定义可匹配的data。
-
data由 两部分组成:mimeType 和Url。
说明:Url默认值为 content和 file。如果Intent指定完整的data,必须调用setDataAndType方法。
1.4 问题扩展
1.onStart和onResume、onPause和onStop 从描述上差不多,对我们来说有什么实质上的不同?
答:onStart和onResume是从Activity是否可见的角度来回调的,onPause和onStop是从Activity是否在前台来回调的。
2.假设当前Activity为A,如果这时用户打开一个新ActivityB,那么B的onResume和A 的onPause哪个先执行?
答:A的onPause先执行。
3.当系统配置发生变化时,Activity会被重新创建,有什么办法能够不重新创建?
答:可以给Activity指定configChanges属性。例如不想让Activity旋转时重新创建,可以给configChanges属性添加orientation这个值。
android:configChanges="orientation"
本文参考:
《Android开发艺术探索》