您的位置:首页 > 移动开发 > Android开发

android基础之IntentFilter匹配规则与隐式启动Activity

2015-08-02 15:35 726 查看

1 Intent Filter匹配规则

  Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intent的action/type/category这三个属性来进行匹配判断的。

  一个过滤列表中的action/type/category可以有多个,所有的action/type/category分别构成不同类别,同一类别信息共同约束当前类别的匹配过程。只有一个Intent同时匹配action/type/category这三个类别才算完全匹配,才能启动Activity。

  另外一个组件若声明了多个Intent Filter,例如:多个action,只需要匹配任意一个即可启动该组件。例如:

<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
<data android:mimeType="image/*" />
</intent-filter>


2 action的匹配规则

  action是一个字符串,如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配。一个Intent Filter中可声明多个action,Intent中的action与其中的任一个action在字符串形式上完全相同(注意:区分大小写),action方面才能匹配成功。

<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_TO"/>
</intent-filter>


  只要Intent的action为“SEND”或“SEND_TO”,那么这个Intent在action方面就能和上面那个Activity匹配成功。 

  注意:Activity 间通过隐式 Intent 的跳转,在发出 Intent 之前必须通过 resolveActivity检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常。 

Intent intent = new Intent("android.intent.action.SEND") ;
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e("TAG","activity not found for");
}
}


  Android系统预定义了许多action,这些action代表了一些常见的操作。常见action如下(Intent类中的常量)

Intent.ACTION_VIEW
Intent.ACTION_DIAL
Intent.ACTION_SENDTO
Intent.ACTION_SEND
Intent.ACTION_WEB_SEARCH


3 data的匹配规则

3.1 data的匹配规则解析

  如果Intent没有提供type,系统将从data中得到数据类型。和action一样,同action类似,只要Intent的data只要与Intent Filter中的任一个data声明完全相同,data方面就完全匹配成功。

  (1)data由两部分组成:mimeType和URI。Intent的uri可通过setData方法设置,mimetype可通过setType方法设置;

  (2)MineType指的是媒体类型:例如imgage/jpeg,auto/mpeg4和viedo/*等,可以表示图片、文本、视频等不同的媒体格式;

  (3)URI由scheme、host、port、path | pathPattern | pathPrefix、queryString这5部分组成,例如:

scheme://host:port/path?qureyParameter=queryString


http://www.orangecpp.com:80/tucao?id=hello


  Intent Filter中指定data的语法:

<data android:host="" // 指定数据的主机名,如www.baidu.com
android:mimeType="" // 指定可以处理的数据类型,允许使用通配符的方式进行指定
android:path="" // 主机名和端口之后的部分
android:pathPattern=""
android:pathPrefix=""
android:port="" // 指定数据端口部分
android:scheme="" // 指定数据的协议部分,如http
android:ssp=""
android:sspPattern=""
android:sspPrefix=""/>


3.2 案例1–根据URI传递数据的获取

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("svmplayer://player?name=" + name + "&url=" + url));
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e("TAG","activity not found for");
}
}


if (intent != null) {
videoUrl = URLDecoder.decode(intent.getData().getQueryParameter("url"), "UTF-8");
title = URLDecoder.decode(intent.getData().getQueryParameter("name"), "UTF-8");
}


3.3 案例2–匹配http以 “.pdf” 结尾的路径

  如果我们想要匹配http以 “.pdf” 结尾的路径,使得别的程序想要打开网络pdf 时,用户能够可以选择我们的程序进行下载查看。 我们可以将scheme设置为 “http”,pathPattern 设置为 “.*//.pdf”,整个 intent-filter 设置为:

<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<data android:scheme="http" android:pathPattern=".*//.pdf"></data>
</intent-filter>


  如果只想处理某个站点的 pdf,那么在 data 标签里增加 android:host=”yoursite.com” 则只会匹配 http://yoursite.com/xxx/xxx.pdf,但这不会匹配www.yoursite.com,如果也想匹配这个站点的话,你就需要再添加一个data标签,除 android:host 改为 “www.yoursite.com”,其他都一样。

4 category的匹配规则

  category也是一个字符串,但是它与action的过滤规则不同,它要求Intent中个如果含有category,那么所有的category都必须和过滤规则中的其中一个category相同。也就是说,Intent中如果出现了category,不管有几个category,对于每个category来说,它必须是过滤规则中的定义了的category。

  当然,Intent中也可以没有category(若Intent中未指定category,系统会自动为它带上“android.intent.category.DEFAULT”),如果没有,仍然可以匹配成功。

  特别说明:这二者共同出现,标明该Activity是一个入口Activity,并且会出现在系统应用列表中,二者缺一不可。

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>


5 Intent Filter常见问题汇总

5.1 path、pathPrefix、pathPattern之间的区别

(1)path 用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配;

(2)pathPrefix 用来匹配路径的开头部分,拿上来的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了;

(3)pathPattern 用表达式来匹配整个路径,这里需要说下匹配符号与转义。

5.2 关于隐式intent

  每一个通过 startActivity() 方法发出的隐式 Intent 都至少有一个 category,就是 “android.intent.category.DEFAULT”,所以只要是想接收一个隐式 Intent 的 Activity 都应该包括 “android.intent.category.DEFAULT” category,不然将导致 Intent 匹配失败。例如:说一个activity组件要想被其他组件通过隐式intent调用, 则其在manifest.xml中的声明如下。

<activity android:name="com.wooyun.org.MainActivity">
<intent-filter>
<action android:name="com.google.test" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>


5.3 于intent-filter匹配优先级

  首先查看Intent的过滤器(intent-filter),按照以下优先关系查找:action->data->category。

6 自定义隐式Intent

(1)比如有一个Activity名称为SecondActivity,在AndroidManifest.xml中配置:

<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.ACTION_SECOND"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>


(2)启动的时候

Intent intent = new Intent("com.example.ACTION_SECOND");
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e("TAG","activity not found for");
}
}


(3)只有action和category中的内容同时匹配上Intent中指定的action和category时,该Activity才能响应该Intent。android.intent.category.DEFAULT是默认的category,在调用startActivity方法时会自动将这个category添加到Intent中。可以为一个Activity指定多个category,即在SecondActivity中多添加一个category。

<category android:name="com.zjq.activity.CUSTOM_CATEGORY"/>


(4)则在启动SecondActivity时:

Intent intent = new Intent("com.zjq.activity.ACTION_SECOND");
intent.addCategory("com.zjq.activity.CUSTOM_CATEGORY");
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e("TAG","activity not found for");
}
}


7 系统定义的Action

(1)启动浏览器并打开某个网页

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e("TAG","activity not found for");
}
}


(2)跳转到拨号界面

Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:10086"));


8 参考链接

你必须弄懂的Intent Filter匹配规则

Android隐式启动Activity
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android