前言:
Activity作为四大组件之一,中文翻译直接翻译为“活动”,是日常应用中与用户交互的接口,它提供了供用户操作的窗口,正常情况下,除了Window、Dialog和Toast,我们能见到的界面只有Activity。
学习清单:
Activity
的生命周期Activity
的启动模式IntentFilter
的匹配规则
一、Activity
的生命周期
1.1 典型情况下的生命周期分析
1.1.2 Activity常用的生命周期
onCreate
:表示Activity
正在被创建,生命周期的第一个方法。onRestart
:表示Activity
正在重新启动。onStart
:表示Activity
正在被启动。onResume
:表示Activity
是可见的,出现在前台并且开始活动。onPause
:表示Activity
正在停止。onStop
:表示Activity
即将停止。onDestory
:表示Activity
即将被销毁。
图 1-1
问:一个Activity的生命周期中可能会出现哪几种情况?
(1)Activity
第一次启动时,回调有:onCreate
-> onStart
-> onResume
。
(2)用户打开新的Activity或者切换到桌面时:onPause
-> onStop
。若Activity采用了透明主题,则Activity
不会回调onStop
。
(3)用户再回到原Activity时:onRestart
-> onStart
-> onResume
。
(4)用户按Back键回退时:onPause
-> onStop
-> onDestroy
。
(5)当Activity
被系统回收再打开时,生命周期与(1)一样。
(9)onCreate
和onDestroy
分别标识着Activity
的创建和销毁,在整个生命周期中只有一次调用。
问:onStart
、onStop
和onResume
、onPause
有什么区别?
onStart
和onStop
分别标识着Activity
的开始和停止,前者Activity
可见,后者Activity
不可见。onResume
和onPause
分别标识着Activity
的继续和暂停。前者Activity
在前台,后者Activity
在后台。
1.2 异常情况下的生命周期分析
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
之后。
1.1.2资源内存不足导致优先级低的Activity被杀死
Activity优先级从高到低可以分为以下三种:
前台
Activity
——正在和用户交互的Activity
,优先级最高。可见但并非前台
Activity
——比如Activity
中弹出一个对话框,导致Activity
可见,但是位于后台无法和用户交互。后台
Activity
——已经被暂停的Activity
,比如执行了onStop
,优先级最低。
当系统内存不足时,系统就会按照上述优先级去杀死目标Activity
所在的进程,并在后续onSaveInstanceState
和onRestoreInstanceState
来存储和恢复数据。
1.2 Activity
的启动模式
1.2.1 Activity
的LaunchMode
任务栈:一种“先进后出”的栈结构,存放
Activity
实例。
问: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.3 IntentFilter
的匹配规则
启动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,如果这时用户打开一个新Activity
B,那么B的onResume
和A 的onPause
哪个先执行?
A的
onPause
先执行。
3.当系统配置发生变化时,Activity会被重新创建,有什么办法能够不重新创建?
可以给Activity指定
configChanges
属性。例如不想让Activity旋转时重新创建,可以给configChanges
属性添加orientation这个值。android:configChanges="orientation"
本文参考:
- 《Android开发艺术探索》
- IntentFilter的匹配规则