活动有四种默认的启动方式,standard,singleTop,singleTask,singleInstance。
对于设置为标准模式的活动,在别的活动启动它时,它会加入到启动它的那个活动的任务栈中,而且每被启动一次,就会创建一个实例。有一种情况就是,活动1->活动2->活动3->活动1,这时候的活动1并不是先前的活动1,所以会发现所有之前的在视图上的数据都会是0,但是通过不停地点击back键,就会又出现有数据的活动1了。
singleTop模式,设置为该模式的活动,被启动时也是被加到启动它的活动的任务栈中,唯一多出来的功能就是,当启动自己的任务栈的栈顶就是自己时,不会创建多个实例,也就是说,singleTop的一个作用就是解决standard模式的一种奇怪现象,就是在栈顶启动自己时,明明已经是自己了,却还是多余地创建自己的实例,导致在点击后退键时,同样的活动实例一个个出现,使得后退键出现似乎失效的情况,但是还是没能解决上面提到的那种情况。
singleTask模式,设置了该模式的活动,像是在singleTop的基础上,添加了向栈内搜索的功能,一旦搜索到了,就将位于活动上方的活动全部出栈,然后让目标活动位于栈顶;与此同时,singleTask模式移除了standard模式的依赖属性,该模式的活动被启动后会被添加到自己指定的任务栈中,指定方式为指定属性TaskAffinity的指定栈名,如果指定栈不存在,则创建一个使用该名的栈。默认情况下,所需任务栈的名字为应用的包名。
singleInstance模式,设置了该模式的活动,等于是在singleTask模式下,固定地使TaskAffinity的值为非包名,也就是一定会为改模式下的活动创建自己的任务栈,当任务栈存在时,接下来的操作与singleTask一样。
每个任务栈都分为前台任务栈和后台任务栈,其实也就是栈里太后的直接分到另一个栈里了。整体上还是一个任务栈。
对于使用ApplicationContext启动标准模式的活动是会报错的,因为ApplicationContext没有任务栈,解决办法是给intent添加标记位:FLAG_ACTIVITY_NEW_TASK。其内在其实是以singleTask模式启动。
活动还有一个属性叫allowTaskReparenting,当它为true时,该活动被启动时,如果自己所属的应用没有在运行,也就是自己所属的任务栈没有被创建时,则允许被加入到调用自己的那个应用的任务栈中,但当自己的应用被开启,也就是自己本来TaskAffinity指定的任务栈被创建时,则自己会去到自己任务栈的栈顶,也就是自己的应用打开时会直接显示自己。
可以通过在命令行端输入adb shell dumpsys activity来查看执行的任务栈情况。
关于活动的FLAG设置,在大多数的情况下是不需要为活动设置标记位的。比较常用的标记位有:FLAG_ACTIVITY_NEW_TASK,FLAG_ACTIVITY_SINGLE_TOP,FLAG_ACTIVITY_CLEAR_TOP,FLAG_ACTIVITY_EXCLUED_FROM_RECENTS。
在过滤列表Intent-filter中,action,category,data都是可以有多个的,甚至Intent-filter都是可以有多个的。其中,对于intent而言,action和data,如果目标活动都设置过滤,则必须有指定的action和data,category则不一样,如果目标活动有设置默认DEFAULT,则intent可以在不指定category的情况下启动目标活动,因为系统会在调用startActivity或者startActivityForResult时位intent自动地带上默认category。
action和category都是字符串,而data则不是,它可以分为URI部分和mineType部分,mineType是指媒体类型。URI的组成如下:
其中,schema用的比较多的是http,file,content等,pathPattern是指一些通配符,pathPrefix是文件前缀。如果schema和host没有指定,则整个URI是无效的。如果过滤列表里没有指定URI,只指定了mineType,则intent在写入data时,schema必须指定为content或者file,后面再接上host,因为过滤表没有写默认为content或file。设置intent的data,使用setDataAndType。
对于Service和BroadcastReceiver,这种过滤表同样适用,只是对于服务,不提倡适用过滤表,而是直接显示开启。
当intent指定的活动没有匹配到时,应用是会奔溃的,为了防止这种情况,我们可以通过PackageManager或者Intent的resolveActivity(intent,FLAG)来检验,返回null则表示没有可以匹配的活动。PM还有另一个方法,queryIntentActivities(intent,FLAG),不同的是会返回所有可以匹配的活动。对于FLAG,一般指定MATCH_DEFAULT_ONLY,因为如果不这样,当intent没有指定category时,PM如果返回非null,该活动是有可能没有指定DEFAULT的,而系统又会帮我们的intent加上DEFAULT,这样就不匹配了,就会导致活动启动失败,也就等于误判了,也就是说,PM或者Intent的这个方法不会预算系统为intent自动加上的DEFAULT,所以要加上MATCH_DEFAULT_ONLY的FLAG。