4.Intent-filter的匹配规则

 启动Activity的方式有两种,一种是显式调用,一种是隐式调用。显式调用就是明确指定了启动对象的组件信息,包括了包名和类名。而隐式调用不需要明确指定组件的信息。显示调用很简单,比如我们常用的
            Intent intent = new Intent( mContext , XXActivity.class);    
        或者是使用:
            ComponentName componentName = new ComponentName( "com.xx.xx","com.xx.xx.XXActivity");
            Intent intent = new Intent();
            intent.setComponent( componentName);
            startActivity( intent );
    这些都是使用显式调用。而隐式调用就比较复杂了,隐式调用要求Intent能够匹配目标组件(不一定是Activity)的IntentFilter中所设置的过滤信息,如果不匹配将无法启动目标Activity。
    IntentFilter中的过滤信息有action、category、data。
    为了匹配过滤列表,需要同时匹配过滤列表中的action、category、data信息,否则匹配失败。一个过滤列表中的action、category和data可以有多个。所有的action、category、data分别构成不同的类表,同一个类别的信息共同约束当前类别的匹配过程,只有一个Intent同时匹配了action类别,category类别,data类表才算完全匹配,只有完全匹配才能成功启动目标Activity,另外一点,一个Activity中可以有多个intent-filter,一个Intent只要能够匹配任何一组intent-filter就可以成功启动对应的Activity。
  
    1.action的匹配规则
    action是一个字符串,系统已经预定义了一些action(非常多最最常见的就是:android.intent.action.MAIN),同时我们也可以在应用中定义自己的action。比如com.mapbar.android.OUT_CALL_NAVI .action的匹配规则是Intent 中的action必须要和intentFilter中的action匹配,这里的匹配是指字符串值一模一样。一个intentFilter可以有多个action,那么只要Intent中的action能够和过滤规则中的任何一个action相同就可以匹配成功。另外要注意了,action是必须要设置的,如果没有设置action那么就会匹配失败。
    故:action的匹配,要求Intent中的action存在并且必须和IntentFilter中的其中一个action相同,action匹配规则和category不同。此外,它是区分大小写的。

    2.category的匹配规则
    这里先介绍category的意义,category属性用于指定当前动作(Action)被执行的环境,一般是理解为对Action的补充,我认为,action其实也可以做到这个,只要你定义的action够多,但是,这样子做的话,那就不符合面向对象设计的思想,至少,action没有复用,而且看起来结构性也很差。个人是这样理解的。
    系统预定义了一些category,同时我们也可以自定义一些category.category的匹配规则和action不同,它要求Intent中如果含有category,那么所有的category都必须和过滤规则中的其中一个category相同,换句话说,如果在Intent中出现了category那么,就要求这些category每一个的内容都必须要和IntentFilter中的某一个完全匹配,否则就会匹配失败。而如果没有添加category就默认匹配成功,因为在Actity当中有一个默认的category“android.intent.category.DEFAULT”这个category。而startActivity和startActivityForResult默认会添加这个category。如果想要让Activity能够接收隐式调用,那么就要在Intent-filter的category加上“android.intent.category.DEFAULT",例外情况是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中没有必要加入android.intent.category.DEFAULT,当然加入也没有问题.
    3.data的匹配规则
    data的匹配规则和action类似,如果过滤规则中定义了data,那么Intent中必须也要定义匹配的data,在介绍data匹配规则之前,我们先了解一下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由2个模块组成:
  • mimeType:媒体类型,比如image/jpeg、audio/mpeg4-generic 和video/*等,可以表示图片、文本、视频等不同的媒体格式。
  • URI:URI中包含的数据比较多,URI结构如下:
        <scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
    上面的URI是很常见的,不过在这边还是都介绍下
  • Scheme:URI的模式,比如http、file、content等,如果没有制定scheme,那么URI整个都是无效的。
  • Host:主机名,比如www.baidu.com,如果host未指定,那么整个URI中的其他参数无效,这也意味着URI是无效的。
  • Port:URI的端口号:比如80.仅当URI中指定了scheme和host参数的时候port参数才是有意义的。
    
    path、pathPattern、pathePrefix:这三个参数表述路径信息,其中path表示完整的路径信息:pathPattern也表示完整的路径信息,但是它里面可以包含通配符"*","*"表示0个或者多个任意字符,需要注意的是,由于正则表达式的规范,如果想要表示真实的字符串,那么"*"要写成"\\*","\"要写成"\\\\"(思考一下为什么是四个),pathPrefix表示路径的前缀信息。  
    介绍完data的数据格式后,我们要说一下data的匹配规则了,data匹配规则和Action相似,要求Intent中必须有data数据,并且和IntentFilter其中一个data完全匹配。这里的完全匹配是指过滤规则中出现的data部分也出现在Intent的data中。
    比如如下的过滤规则
    <intent-filter>
        <data android:mimeType="image/*" />
        …………
    </intent-filter>

    匹配时可以写成如下:
    intent.setDataAndType(Uri.parse("file://abc"),"image/png");

    另外,要指定完整的data 必须要调用setDataAndType方法,不可以先setData再setType,因为两者会清楚对方的值。

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

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

上面这两个写法效果是一样的。
考虑一下这个情形:    
    
<intent-filter>
        <data android:scheme="file" />
        <data android:host="www.qq.com"/>
        <data android:scheme="http"/>
    </intent-filter>
这个情况又是如何呢?

   Intent-filter的匹配规则对于Service和BroadcastReceiver也是同样的道理,不过系统对于Service的建议是尽量使用显式调用来启动服务。

    当我们是用隐式调用来启动一个Activity的时候,我们可以做一下判断,看看是否有Activity能够匹配我们的隐式Intent,如果不做判断就有可能出现ActivityNotFoundException.

    判断方法有2种:
  • 采用PackManager的resolveActivity方法
  • 采用Intent的resolveActivity方法。
    上述方法找不到匹配的Activity就会返回null.通过判断返回值就可以规避上面的那个异常。此外,PackageManager还提供了queryIntentActivities方法,这个方法和resolveActivity方法不同的是,它不是返回最佳匹配的Activity信息,而是返回所有成功匹配的Activity信息。我们看一下queryIntentActivities和resolveActivity的方法原型:
     public abstract List<ResolveInfo> queryIntentActivities( Intent intent , int flags);
    public abstract ResolveInfo resolveActivity(Intent intent ,int flags);

上面方法的第一个参数很好理解,关键在于第二个参数。我们要使用MATCH_DEFAULT_ONLY 这个标记位,这个标记位含义是只匹配那些声明了<category android:name="android.intent.category.DEFAULT"/>这个category的Activity。使用这个标记位的意义在于,只要上上述两个不返回null,那么startActivity一定可以成功。如果不用这个标记位,就可以把不含Default的那些Activity匹配出来,导致失败,因为不含有DEFAULT这个category的activity是无法接收隐式Intent的.例外的情况是这一类的action和category:
    <action android:name="android.intent.action.MAIN">
    <category android:name="android.intent.category.LAUNCHER"/>
这两者是用来表明这是一个入口Activity,并且会出现在系统应用列表当中,少了其中任何一个都没有实际的意义,也无法出现在系统的应用列表当中。另外,对于service和broadcastReceiver、PackManager同样提供了类似的方法去获取成功匹配的组件信息。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值