1. Activity的生命周期和启动模式《Android开发艺
2018-06-22 本文已影响0人
tesla1984
1.1 Activity的生命周期全面分析
-
典型情况下生命周期
- onPause先执行完,新Activity的onResume才会执行
- 当用户打开新Activity或者切换到桌面的时候,onPause->onStop。有一种特殊情况,如果新Activity采用透明主题,那么当前Activity不会回调onStop
- onStart和onStop是从Activity是否可见这个角度来回调的
- onResume和onPause是从Activity是否位于前台这个角度来回调的
-
异常情况下生命周期
- 资源相关的系统配置发生变化导致Activity被杀死并重新创建(如横屏)
- 当系统配置发生改变后,Activity会被销毁,onPause,onStop,onDestroy都会调用
- Activity异常终止,系统会调用onSaveInstanceState来保存当前Activity的状态,这个方法的调用在onStop之前,和onpause没有既定的时间关系,可能在onPause之前,也可能在onPause之后
- 资源内存不足导致低优先级Activity被杀死(数据存储和恢复过程和上面一致)
- 资源相关的系统配置发生变化导致Activity被杀死并重新创建(如横屏)
1.2 Activity的启动模式
- Activity的LaunchMode
-
standard
ApplicationContext启动standard模式Activity会报错,因为standard模式的Activity默认会进入启动它的Activity所属的任务栈,但是由于非Activity类型的Context(如ApplicationContext)并没有所谓的任务栈,解决这个问题的方法就是为待启动Activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就会为它创建一个新的任务栈,这个时候启动Activity实际上是以singleTask模式启动的 -
singleTask
当一个具有singleTssk模式的Activity请求启动后,比如Activity A,系统首先会寻找是否存在A想要的任务栈,
如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放到栈中。如果存在A所需要的任务栈,
这时要看A是否在栈中有实例存在,如果有实例存在,那么系统就会把A调到栈顶并调用它的onNewIntent方法,如果实例不存在,就创建A的实例并把A压入栈中
singleTask默认具有clearTop的效果 -
singleInstance
具有此种模式的Activity只能单独位于一个任务栈中。由于栈内复用的特性,后续请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁 - 任务栈
- TaskAffinity该参数标识了一个Activity所需要的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用包名。
- TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,其他情况下没意义
- 任务栈氛围前台任务栈和后台任务栈
- 当TaskAffinity和allowTaskReparenting结合使用的时候,比如现在有2个应用A和B,A启动了B的一个Activity C,然后按Home键回到桌面,然后再单击B的桌面图标,这个时候并不是启动了B的主Activity,而是重新显示了已经被应用A启动的Activity C,或者说,C从A的任务栈转移到了B的任务栈中。可以这么理解,由于A启动了C,这个时候C只能运行在A的任务栈中,但是C属于B应用,正常情况下,它的TaskAffinity值肯定不可能和A的任务栈相同(因为包名不同)。所以,当B被启动后,B会创建自己的任务栈,这个时候系统发现C原本所想要的任务栈已经被创建了,所以就把C从A的任务栈中转移过来了。
- 通过Manifest指定启动模式无法直接为Actiivty设定FLAG_ACTIVITY_CLEAR_TOP标识
- 通过Intent指定启动模式无法为Activity指定singleInstance模式
-
standard
1.3 IntentFilter的匹配规则
- action的匹配规则
action的匹配要求Intent中的action存在且必须和过滤规则中的其中一个action相同。action区分大小写 - category的匹配规则
- category要求Intent可以没有category,但是如果一旦有category,不管有几个,每个都要能够和过滤规则中的任何一个category相同。
- 为什么不设置category也可以匹配?因为系统在调用startActivity或者startActivityForResult会默认为Intent加上“android.intent. category.DEFAULT”这个category,所以这个category就可以匹配前面的过滤规则中的第三个category。同时,为了我们的activity能够接收隐式调用,就必须在intent-filter中指定“android.intent.category.DEFAULT”这个category,原因刚才已经说明了。
- data的匹配规则
- data的语法如下所示。
<data android:scheme="string" android:host="string" android:port="string" android:path="string" android:pathPattern="string" android:pathPrefix="string" android:mimeType="string" />
- data由两部分组成,mimeType和URI。mimeType指媒体类型,比如image/jpeg、 audio/mpeg4-generic和video/*等,可以表示图片、文本、视频等不同的媒体格式,而URI中包含的数据就比较多了,下面是URI的结构:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
- 匹配规则
这种规则指定了媒体类型为所有类型的图片,那么Intent中的mimeType属性必须为“image/*”才能匹配,这种情况下虽然过滤规则没有指定URI,但是却有默认值,URI的默认值为content和file。也就是说,虽然没有指定URI,但是Intent中的URI部分的schema必须为content或者file才能匹配,这点是需要尤其注意的。为了匹配(1)中规则,我们可以写出如下示例:<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
intent.setDataAndType(Uri.parse("file://abc"),"image/png")。
另外,如果要为Intent指定完整的data,必须要调用setDataAndType方法,不能先调用setData再调用setType,因为这两个方法彼此会清除对方的值,这个看源码就很容易理解,比如setData:
可以发现,setData会把mimeType置为null,同理setType也会把URI置为null。public Intent setData(Uri data) { mData = data; mType = null; return this; }