参考
Intent
概述
Intent对象可以向操作系统描述我们需要处理的任务。使用显式Intent,我们需要指定具体的类名;而使用隐式Intent,我们只需要向操作系统描述清楚我们的工作意图,操作系统会去启动那些对外宣称能够完成任务的activity(即能匹配成功intent-filter的)。如果操作系统找到多个activity,那么用户将会看到可选列表,然后看用户自己如何选择了。通过隐式意图启动一些组件时,必须满足该组件所对应的<intent-filter>。
虽然隐式意图也可以带extra数据,但操作系统在寻找合适的activity时并不会使用任何附加在隐式意图上的extra信息。这并不意味着隐式意图上的extra信息没有用,同显式意图一样,intent一样会将它所带的extra信息带到寻找到的activity中。
flag
FLAG_ACTIVITY_NEW_TASK:例如现在栈1的情况是:A B C。C通过intent跳转到D,并且这个intent添加了FLAG_ACTIVITY_NEW_TASK标记,如果D这个Activity在Manifest.xml中的声明中添加了Task affinity,系统首先会查找有没有和D的Task affinity相同的task栈存在,如果有,将D压入那个栈,如果不存在则会新建一个D的affinity的栈将其压入。如果D的Task affinity默认没有设置,则会把其压入栈1,变成:A B C D,这样就和不加FLAG_ACTIVITY_NEW_TASK标记效果是一样的了。(参见)。注意:从非activity开启activity的话,必须为intent设置该标签。
FLAG_ACTIVITY_NO_HISTORY:当前启动的activity不会在栈中存在,也就是说,按返回键的时候是没有办法返回到该activity的。和<activity>中的noHistory=true是一样的效果。
<intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="inline" />
<data android:mimeType="text/html"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="application/xhtml+xml"/>
<data android:mimeType="application/vnd.wap.xhtml+xml"/>
</intent-filter>
可以看出<intent-filter>有三个子结点<action>,<category>,<data>。
<action>
<category>
它指intent的可选类别,常用来描述我们何时、何地甚至如何使用某个activity。通过Intent#addCategory()为Intent对象设置category。它会自动匹配<intent-filter>中的<category>结点。
设置category时,用的是add,而且Intent#getCategories()返回的是一个Set集合,这表明一个Intent可以含有多个category。同理<intent-filter>中也可以设置多个<category>。
匹配规则:如果Intent中没有定义category属性,那么会匹配成功。如果Intent中定义了category,无论是多少个,每一个都必须是在<intent-filter>中定义过的,否则会匹配不成功。也就是说addCategory()指定的category值必须是<category>指定的子集。
此处需注意一点
如果该intent传入到startActivity()中当作参数,系统会默认的加上一个值为android.intent.category.DEFAULT的category。因此,如果<intent-filter>没有设置<category android:name="android.intent.category.LAUNCHER" />它是不会被隐式意图启动的。
<data>
要操作的数据及数据类型。可以通过Intent.setType(),Intent.setData()和Intent.setDataAndType()为Intent对象设置数据和数据类型。前两个方法分别用来设置类型和数据,但由于setType()与setData()两个方法互斥,后写的方法会清空掉前写的方法所设置的值,所以如果同时要设置type与data应调用Intent.setDataAndType(),而不是分别调用前两个方法。
匹配规则:如果Intent中没有设置data,但<intent-filter>中定义了,则匹配不成功。其余见下面Uri部分。
它的具体属性值如下:
android:mimeType,应该通过intent.setType(type)来匹配mimeType的值,表示数据类型。
android:scheme:指向的是Uri中的scheme的值。
android:path:指向的是Uri中的path的值。
android:port:指向的是Uri中的port的值。
android:host:指向的是Uri中的host的值。
Uri
Intent.setData()中的参数是一个Uri,而对于一个Uri来说,它的标准样式如下:
scheme://host:port/path
当没有设置host的值时,port,path的值是无效的,并且data并不是完全匹配的。只要传入的Uri中的scheme,host,port,path分别满足<intent-filter>中的对应的值,该activity就会启动。假如:一个<intent-filter>中设置了scheme,host,port。而一个Uri中的scheme,host,port匹配相应的值,而且该Uri中还有path,那么这个<intent-filter>对应的activity也会启动。例如下面的intent是可以匹配下面的intent-filter,虽然intent比<intent-filter>在data上多了host值:
Intent对象
Intent intent = new Intent("xx");
intent.addCategory("xxxx");
intent.setData(Uri.parse("ab://dafdaf"));
startActivity(intent);
intent-filter
<intent-filter>
<action android:name="xx" />
<category android:name="xxxx" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="ab"/>
</intent-filter>
如果Intent中没有传入Uri,也没有传入type,只有filter中同样没有指定uri和type时才能匹配成功。
注意事项
在使用隐式意图调用别的activity时,如果没有activity满足该intent对象,那么程序就会崩溃。因此,在调用隐式意图之前需要判断有没有activity能满足当前的隐式意图。判断的代码如下:
public boolean hasActivities(Intent intent) {
PackageManager pm = getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
return activities.size() > 0;
}
当系统中有多个应用可以响应当前的intent,默认情况下会弹出一个dialog,让用户进行选择,并且在选择的时候设置成默认的打开应用。
一旦将某个应用设置成默认的打开应用,那么下次该种类型的intent会直接使用该应用打开,而不会再弹出dialog让用户进行选择。如果想每一次都让用户进行选择,那么可以使用Intent.createChooser(Intent,String),其中第二个参数为弹出dialog中的title,第一个参数为要响应的intent。该方法也会返回一个intent对象,将该对象直接使用到startActivity或者startActivityForResult()中即可。
一般地,第二个参数使用PackageManager.MATCH_DEFAULT_ONLY。该参数的含义是:仅匹配在<intent-filter>中添加了android.intent.category.DEFAULT的category,如果没有即使别的所有的都匹配成功也不会返回。这样就避免了在startActivity()的时候造成崩溃。这是因为startActivity()的时候,intent默认是添加上了DEFAULT的category,所以<intent-filter>中如果没有该值的话,在启动时是无法启动的,从而可能造成崩溃。