Android里Activity的IntentFilter匹配规则

Activity的启动方式

显式启动

显示方式就是在通过intent启动Activity时指定了Activity的包名和类名,而且不管启动本应用的Activity还是启动其他应用的Actitity

例如:要启动的Activity是同一个项目之中:

Intent intent = new Intent(context, MyActitity.class);
startService(intent);

如果因为也是在同一个项目之中,但特殊原因不能直接引用XXXActivity,也可以通过loadClass,传入完整的包名来启动Activity:

try {
    Class c = context.getClassLoader().loadClass("com.xxx.MyActivity");
    Intent intent = new Intent(context, c);
    startActivity(context, intent);
} catch(ClassNotFoundException ex) {
    ex.printStackTrace();
}

又例如:要启动的Activity不在同一个项目之中:

ComponentName cn = new ComponentName("packageName",com.xxx.MyActivity");
Intent intent = new Intent();
intent.setComponent(cn);
startActivity(intent);

或者:

Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("packageName","com.xxx.MyActivity");
startActivity(intent);

隐式启动

隐式启动Activity需要同时匹配过滤列表中的action、category、data信息。action、category和data可以有多个,同一类别的信息共同约束当前类别的匹配过程。一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应用Activity。

下面是一个过滤规则的示例:

<activity
    android:name="com.xxx.MyActivity"
    android:configChanges="screenLayout"
    android:label="@string/app_name"
    android:launchMode="singleTask"
    android:taskAffinity="com.xxx">
    <intent-filter>
        <action android:name="com.xxx.a"/>
        <action android:name="com.xxx.b"/>
        <category android:name="com.xxx.c"/>
        <category android:name="com.xxx.d"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

匹配实例代码:

Intent intent = new Intent("com.xxx.a");
intent.addCategory("com.xxx.c");
intent.setDataAndType(Uri.parse("file://abc"), "text/plain");
startActivity(intent);

action的匹配规则

action是一个字符串,系统预定义了一些action,同时我们也可以在应用中定义自己的action,action区分大小写。action的匹配规则是Intent中的action必须能够和过滤规则中的action字符串完全一样。一个过滤中可以有多个action,Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功。

category的匹配规则

category是一个字符串,系统预定义了一些category,同时我们也可以在应用中定义自己的category。category要求Intent中如果含有category,不管有多少个,都必须和过滤规则中的其中有定义的category相同。当然,Intent中可以没有category,如果没有category的话,按照上面的描述,这个Intent仍然可以匹配成功。原因是系统在调用startActivity或者startActivityForResult的时候会默认为Intent加上”android.intent.category.DEFAULT”这个category,所以这个category就可以匹配前面的过滤规则中的第三个category。同时,为了我们的activity能够接收隐式调用,就必须在intent-filter中指定”android.intent.category.DEFAULT”这个category。即是说,在Intent中可以没有category,但有的情况下,哪怕是其中一个都不能无中生有。

data的匹配规则

 data的匹配规则和action类似,如果过滤规则中定义了data,那么Intent中必须也要定义可匹配的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>]

scheme:                       URI的模式,比如http、file、content等。如果URI中没有指定scheme,那么整个URI的其它参数无效,这也意味着URI是无效的。    

host:                              URI的主机名,比如www.baidu.com,如果host未指定,那么整个URI中的其他参数无效,这也意味着URI是无效的。    

port:                              URI中的端口号,比如80,仅当URI中指定了scheme和host参数的时候port参数才是有意义的。    

path、pathPattern和pathPrefix: 这三个参数表述路径信息,其中path表示完整的路径信息;pathPattern也表示完整的路径信息,但是它里面可以包含通配符“*”,“*”表示0个或多个任意字符,需要注意的是,由于正则表达式的规范,如果想表示真实的字符串,那么“*”要写成“\\*”,”\”要写成”\\\\”;pathPrefix表示路径的前缀信息。

分情况说明data的匹配规则

1、 如下过滤规则:

 <intent-filter>
   <data android:mimeType="image/*"/>
</intent-filter>

匹配实例:

intent.setDataAndType(Uri.parse("file://abc"),"image/png")

说明:

这种规则mimeType属性必须为“image/*”才能匹配,虽然过滤规则没有指定URI,但是却有默认值,URI的默认值为content和file。

2、 如下过滤规则:

<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http" android:host="abc" />
    <data android:mimeType="audio/mpeg" android:scheme="http" android:host="abc" />
 </intent-filter>

匹配实列:

intent.setDataAndType(Uri.parse("http://abc"),"video/mpeg")

或者

intent.setDataAndType(Uri.parse("http://abc"),"audio/mpeg")

特殊写法

如下两种特殊写法,它们的作作是一样的:    

<intent-filter …>
   <data android:scheme="file" android:host=”www.baidu.com”/>
   …
</intent-filter>

 和

<intent-filter …>
   <data android:scheme="file" />
   <data android:host=”www.baidu.com”/>
   …
</intent-filter>

错误规避

当我们通过隐式方式启动一个Activity时,如果没有匹配Activity则会出现错误,所以我们在匹配前可以使用PackageManager的resolveActivity方法或者Intent的resolveActivity方法。如果它们找不到匹配的Activity则返回null。PackageManager还提供了queryIntentActivities方法,这个方法不是返回最佳匹配的Activity信息,而是返回所有成功匹配的Activity信息。

有时,可以在startActivity前,先判断Intent是否有效,可以这样:

private static boolean isIntentAvailable(Context context, Intent intent) {
    if (intent == null) {
        return false;
    }
    boolean isAvailable = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
    return isAvailable;
}

入口Activity

<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />

以上代码,二者共同作用是用来标明这是一个入口Activity并且会出现在系统的应用列表中,少了任何一个都没有实际意义。

 

 


——本博文部分内容参考自《Android开发艺术探索》

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值