Activity生命周期和启动模式
1. 典型情况下的生命周期分析
-
完整生存期:onCreate()-onDestory(),分别标识着Activity的创建和销毁,并且只可能有一次调用。 -
可见生存期:onStart()-onStop(),随着用户的操作或者设备屏幕的点亮和熄灭,这两个方法可能被调用多次。 -
前台生存期:onResume()-onPause(),随着用户操作或者设备屏幕的点亮和熄灭,这两个方法可能被调用多次。
当用户按下back键回退时,回调如下:onPause()-onStop()-onDestory()。
假设当前Activity为A,这时用户打开一个新的Activity B,那么此时的生命周期回调顺序为:
I/A: onPause()
I/B: onCreate()
I/B: onStart()
I/B: onResume()
I/A: onStop()
因为必须onPause执行完成以后新Activity才能onResume,所以不能在onPause和onStop中做重量级操作,尤其是onPause,这也意味着,我们应当尽量在onStop中做操作,而使得Activity尽快显示出来并切换到前台。
2. 异常情况下的生命周期分析
2.1 情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建
当Activity在异常情况下终止,系统会调用onSaveInstanceState来保存当前Activity的状态,这个方法的调用时机在onStop之前,他和onPause没有既定的时序关系,既可能在onPause之前也可能在其之后。
当Activity被重建后,系统会调用onRestoreInstanceState和onCreate方法来判断Activity是否被重建了,如果是,就取出之前保存的数据并恢复,从时序上来说,onRestoreInstanceState的调用时机在onStrat之后。
关于保存和恢复View层次结构,系统的工作是这样的:首先Activity被意外终止时,Activity会调用onSaveInstanceState去保存数据,然后Activity会委托Window去保存数据,接着Window再委托它上面的顶层容器去保存数据,顶层容器是一个ViewGroup,最后顶层容器再去一一通知他的子元素保存数据,这样整个数据保存工作就完成了。
onSaveInstanceState和onCreate的区别:
- onSaveInstanceState一旦被调用其参数Bundle savedInstanceState一定是有值的,我们不用额外判断它是否为空。
- 如果onCreate正常启动的话,参数Bundle savedInstanceState值为null,所以必须额外判断。
- 这两个方法都可以进行数据恢复,但是建议使用onSaveInsatnceState去恢复数据。
2.2 情况2:资源内存不足导致低优先级的Activity被杀死
Activity按照优先级从高到低,可以分为如下三种:
- 前台Activity:正在和用户交互的Activity,优先级最高。
- 可见但非前台Activity:比如Activity中弹出了一个对话框,导致Activity可见但是位于后台无法与用户直接交互。
- 后台Activity:已经暂停的Activity,比如被执行了onStop,优先级最低。
当系统内存不足时,系统就会按照上述的优先级去杀死目标Activity所在的进程,并在后期通过onSaveInstanceState和onRestoreInstanceState来存储恢复数据。
如果一个进程没有四大组件在执行,那么这个进程很容易被系统杀死。
比较好的方法是将后台工作放入Service中从而保证进程有一定的优先级,这样就不会轻易被系统杀死。
如果当某项内容发生改变后,我们不想系统重新创建Activity,可以给Activity指定configChanges属性
比如不想让Activity在屏幕旋转时重新创建Activity,就可以给configChanges属性添加orientation这个值。
android:configChanges="orientation"
3. Activity的启动模式
3.1 Activity的LaunchMode
-
standard:标准模式,也是默认模式,每次启动一个Activity都会新建一个新的实例 -
singleTop:栈顶复用模式,如果新的Activity已经位于任务栈的栈顶,那么Activity不会被重建,同时他的onNewIntent方法也会被回调,通过此方法的参数我们可以读取出当前请求的信息。 -
singleTask:栈内复用模式,这是一种单例模式,只要Activity在一个栈中存在,那么多次启动Activity都不会创建实例。 比如目前任务栈S1中的情况为ABC,这时候Activity D以singleTask模式请求启动,其所需要的任务栈为S2,由于S2和D的实例均不存在,所以系统会县创建任务栈S2,然后再创建D的实例并将其入栈到S2。 -
singleInstance:这是一种加强的singleTask模式,此模式的Activity只能单独的位于一个任务栈中
3.2 指定启动模式
有两种方法,一种是通过AndroidMenifest.xml文件指定,一种是通过在Intent中设置标志位来为Activity指定启动模式
第一种方式
<activity android:name=".MainActivity"
android:launchMode="singleTask"
android:configChanges="orientation">
第二种方式
Intent intent=new Intent(MainActivity.this,MainActivity2.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
区别:
-
第二种的优先级要高于第一种,当两种同时存在时,以第二种为准。 -
两种方式在限定范围上有所不同,第一种无法直接为Activity设置FLAY_ACTIVITY_CLEAR_TOP标识,第二种无法指定singleInstance模式。
3.3 Activity中的Flags
- FLAG_ACTIVITY_NEW_TASK:指定Activity为singleTask启动模式
- FLAG_ACTIVITY_SINGLE_TOP:指定Activity为singleTop启动模式
- FLAG_ACTIVITY_CLEAR_TOP:具有此表即位的Activity,当他启动时,在同一个任务栈中所有位于他上面的Activity都要出栈,一般与FLAG_ACTIVITY_NEW_TASK配合使用
4. IntentFilter的匹配规则
IntentFilter中的过滤信息有action、category、data。
4.1 action匹配规则
action的匹配规则是Intent中的action必须能够和清单文件过滤规则中的action匹配,这里指字符串值完全一样。
一个过滤规则可以有多个action,那么只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功。
如果Intent中没有指定action,那么匹配失败。
4.2 category匹配规则
category他要求Intent中如果含有category,那么所有的category都必须和过滤规则中的其中一个相同。
换句话说,Intent中如果出现了category,不管有几个category,对于每个category来说,他必须是过滤规则中的存在的category。
Intent中可以没有category,也可以匹配成功,原因是系统在调用satrtActivity或者startActivityForResult的时候会默认为Intent加上"android.intent.category.DEFAULT"这个category,可以与过滤规则中匹配。
所以为了能够接受隐式调用,就必须在intent-filter过滤规则中指定"android.intent.category.DEFAULT"这个category。
4.3 data匹配规则
data匹配规则与action类似,如果过滤规则中定义了data,那么Intent中也必须要定义可匹配的data。
data的语法如下所示:
<data android:scheme="URL模式"
android:host="主机名"
android:port="端口号"
android:path="路径信息"
android:pathPattern="路径信息"
android:pathPrefix="路径信息"
android:mimeType="媒体类型"></data>
如:
<data android:scheme="file"
android:host="www.baidu.com"></data>
|