Android进阶(1)| 深入理解Activity
一.Activity的生命周期
1.典型情况下的生命周期分析
在正常情况下Activity从创建到到销毁会经历如下过程:
(1) onCreate():
- 调用前:Activit刚刚启动
- 调用时:进行一些初始化的工作
- 调用后:准备调用onStart()
(2) onStart():
- 调用前:onCreate()方法刚结束
- 调用时:Activity正在被启动
- 调用后:Activity已经显示出来,但是无法进行交互。准备调用onResume()
(3)onResume():
- 调用前:onStart()刚结束
- 调用时:Activity由后台开始转移到前台
- 调用后:Activity对于用户来说完全可见并且可以进行交互。准备调用onPause()
(4)onPause():
- 调用前:onResume()刚结束
- 调用时:Activity正在停止
- 调用后:Activity已经不可见。准备调用onStop()
(5)onStop():
- 调用前:onPause()刚结束
- 调用时:Activity即将停止
- 调用后:Activity正在停止或即将被销毁。准备调用onDestroy()
(6)onDestroy():
- 调用前:onStop()刚结束
- 调用时:Activity即将被销毁
- 调用后:Activity被销毁,调出任务栈
特殊:onRestart():
- 调用前:onStop()刚结束
- 调用时:Activity正在被重新启动
- 调用后:Activity由不可见状态再次变为可见状态。准备调用onResume()
2.Activity生存期
(1)完整生存期
Activity在onCreate()和onDestroy()中所经历的就是完整生存期。我们一般在onCreate()方法中完成一些初始化的操作,在onDestroy()方法中完成释放内存的操作。
(2)可见生存期
Activity在onStart()和onStop()中所经历的就是可见生存期。在这个阶段其实Activity已经是显示了出来,但我们用户不一定看的见,也不一定能够与Activity进行交互操作。
(3)前台生存期
Activity在onResume()和onPause()中所经历的就是前台生存期。在这个阶段中的Activity是可以与用户被用户所见并且进行交互的。
3.异常情况下的生命周期分析
(1)资源相关配置发生改变导致Activity被杀死和重新创建
当系统配置发生变化时,Activity会被销毁,即开始调用onPause()、onStop()和onDestroy(),但是在调用onStop()之前系统会先调用onSaveInstanceState()方法来让当前Activity中的部分数据保存在Bundle中。在Activity销毁之后系统会再次重新创建该Activity,并且在onResume()之前调用onRestoreInstanceState()方法,将Bundle中的数据恢复出来。
注意:系统只在Activity异常终止的时候才会调用onSaveInstanceState()和onRestoreInstanceState()方法,其他正常情况下是不会调用的。
(2)资源内存不足导致低优先级的Activity被杀死和重新创建
优先级:Activity按照优先级从高到低分别是:前台Activity、可见但非前台Activity和后台Activity。
当系统的内存不足时,Activity优先级越低则越容易被系统杀死。当然此时Activity也是处于异常终止,因此生命周期是和第(1)种是一样的,这里就不多分析。
(3)通过修改配置使得Activity在异常情况下不被自动创建
在(1)和(2)中我们分析了Activity在异常情况下的生命周期,它们都是在出现异常时先销毁然后重新创建。不过我们可以修改Activity中的的android:configChanges
属性来指定一些情况下Activity在被销毁之后不被创建。
举例:
android:configChanges:orientation|keyboardHidden
表示当屏幕方向改变或者键盘的可用性发生了改变时Activity在被销毁之后不会重新创建。
注意:当我们设置属性之后Activity不会调用onSaveInstanceState()和onRestoreInstanceState()方法。但是它会调用onConfigChanged()方法。
二.Activity的启动模式
1.深入理解四种LaunchMode
(1)standard
standard模式是Activity默认的启动方式,它启动Activity的具体方式是:每当启动一个活动,就会创建一个该活动的实例,该实例就会在任务栈中入栈并且处于栈顶的位置。
注意:每个Activity实例可以进入不同的任务栈中。例如Activity A和Activity B分别位于栈-1和栈-2当中,当A启动Activity C时,C的实例就会到栈-1的栈顶;当B启动C时,C的另一个实例就会到栈-2的栈顶。
(2)singleTop
singleTop启动的具体方式是:每当启动一个活动时,系统会先查看它所在的任务栈,如果任务栈的栈顶就是该活动,则不会再创建。否则就是和standard模式一样。
(3)singleTask
singleTask的启动方式是:当启动一个活动是,系统会先遍历它所在的任务栈,如果栈中存在该活动的实例,则该活动上方的所有活动都会出栈,也就是说该活动会被推到栈顶。否则还是会在栈顶重新创建一个该活动的实例。
举例:
- 栈-1中从上到下为活动CBA,此时Activity D以SingleTask模式启动,其所需要的任务栈为栈-2,则此时系统会创建一个栈-2并且将D入栈。
- 栈-1情况不变,此时D所需的任务栈为栈-1,则这次系统会将D放入栈-1的栈顶,此时栈-1的情况就是DCBA。
- 假设栈-1此时从上到下是CBDA,此时D启动所需的任务栈是栈-1,则此时栈-1中C和B会出栈,而D不会再次创建实例。栈-1最后的情况就是DA。
(4)singleInstance
singleInstance的启动方式是:活动启动时系统会创建一个新栈,该活动就会单独的在这个栈当中,后面如果再次启动该活动也不会再次创建实例。
2.TaskAffnity属性
TaskAffnity翻译为任务相关性,该参数标识了一个Activity所需要的任务栈的名字。在默认情况下,所有Activity所需的任务栈的名字都是应用的包名,但是我们可以为Activity的TaskAffnity属性单独设定所需栈的名字。
注意:TaskAffnity属性不能设置为包名,否则相当于无效设定;TaskAffnity只能和singleTask启动模式搭配使用,在其他情况下属于没有意义。
3.设置Activity的启动方式
(1)设置android:launchMode
在AndroidMenifest中找到活动的android:launchMode
属性进行修改。
举例:设置Activity为singleTop启动模式android:launchMode:singleTop
。
(2)设置标志位
我们可以在Intent中使用addFlags()方法来设置启动模式。
举例:
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //设置标识位
startActivity(intent);
4.Activity常用的的Flags
1.FLAG_ACTIVITY_NEW_TASK
为Activity指定为singleTask启动模式。
2.FLAG_ACTIVITY_SINGLE_TOP
为Activity指定为singleTop启动模式。
3.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有这个标记的Activity不会出现在历史Activity的列表当中。
三.IntentFilter匹配规则
使用对象:启动Activity的方法有两种:显示Intent和隐式Intent。而在隐式Intent我们就会用到IntentFilter匹配规则。
基本规则:(1)一个intent只有同时匹配某个Activity的intent-filter中的action、category、data中的过滤规则才算完全匹配,才能启动该Activity。 (2)一个Activity可以有多个 intent-filter,一个 intent只要成功匹配任意一组 intent-filter,就可以启动该Activity。
下面来具体介绍每种属性的匹配规则。
1.action匹配规则
匹配规则:Intent中的action必须存在且必须和过滤规则中的任意一个action相同。
注意:在action匹配规则中是区分大小写的,即如果字符相同,但是大小写不同则无法进行匹配。
2.category匹配规则
匹配规则:如果Intent中出现了category,则必须和过滤规则当中的一个category相同;如果Intent中没有出现category,则系统会给Activity默认加上了< category android:name="android.intent.category.DEAFAULT" />
属性值,此时category也能匹配成功。
3.data匹配规则
data的组成:data由两部分组成:mimeType和URI。
匹配规则:如果intent-filter中有定义data,那么Intent中也必须也要含有data数据,并且data数据能够匹配过滤规则中的某一个data。如果没有是定义data过滤规则,则在启动Activity时不用考虑data部分。
注意:(1)data中的过滤规则我们可以分开定义,即我们可以定义<data android:mimeType
和<data android:scheme
。 (2)如果我们只在过滤规则中定义了mimeType,那么URI部分会使用其默认值content或file。也就是说虽然没有指定URI,但是Intent中的URI部分必须是content或file。 (3)在为Intent指定data时我们需要使用setDataAndType()方法。
4.匹配判断的方法
(1)采用PackgeManager的resolveActivity方法,如果找不到匹配的Activity则会返回null。
(2)采用Intent的resolveActivity方法,如果找不到匹配的的Activity则会返回null。