美文网首页SS程序员Android开发
史上最全intent-filter匹配规则,没有之一

史上最全intent-filter匹配规则,没有之一

作者: leo62 | 来源:发表于2016-05-23 09:27 被阅读3615次

    我们知道Activity的启动方式分为隐式和显式两种,至于两者的区别想必大家都已经很清楚了,显式需要明确的指定被启动对象的组件信息,比如包名和类名等,而隐式调用就不需要明确指定组件的信息。隐式调用就需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果匹配不成功就不能启动目标Activity。

    IntentFiler中过滤的信息包含action,category,data,如下边示例所示,本文也将围绕这个示例进行讲解。

    <activity android:name="dbh.leo.com.intentfilter.MyActivity">
        <intent-filter>
            <action android:name="com.leo.a"/>
            <action android:name="com.leo.b"/>
    
            <category android:name="android.intent.category.DEFAULT"/>
            <category android:name="com.leo.c"/>
            <category android:name="com.leo.d"/>
    
            <data android:mimeType="text/plain"/>
        </intent-filter>
    </activity>
    

    总的原则是:

    1. 匹配过滤列表时需要同时匹配过滤列表中的action,category,data;
    2. 一个过滤列表中可以有多个action,category,data并各自构成不同类别,一个Intent必须同时匹配action类别,category类别和data类别才算完全匹配;
    3. 一个Activity中可以有多组intent-filter,一个Intent只要匹配任何一组intent-filter就算匹配成功;

    下边将分别介绍3种属性的匹配规则

    1.action的匹配规则

    我们知道action是一个字符串,系统默认帮我们定义了一些action,同时我们也可以自定义。字符串中的字幕是严格区分大小写的,这个在匹配的时候是要注意的。关于action的匹配很简单,我们可以直接总结归纳一下:

    Intent中必须存在action,这一点和category不同

    action的字符串严格区分大小写,intent中的action必须和过滤规则中的action完全一致才能匹配成功

    匹配规则中可以同时有多个action,但是Intent中的action只需与其中之一相同即可匹配成功

    那么按照以上总结的规则,为了匹配本文开头的示例,那么Intent的action
    可以为“com.leo.a”或者是“com.leo.a”。

    2.category的匹配规则

    和action一样,category也是一个字符串,系统同样默认定义了一些,我们一样可以自定义。其实category的匹配规则和action有很强的可比性,所以我们可以完全类比action来进行总结

    匹配规则中必须添加“android.intent.category.DEFAULT”这个过滤条件;

    Intent中可以不设置category,这个时候你在使用startActivity或者startActivityForResult的时候,
    其实系统自动会为你添加1中的那个默认category;

    Intent中可以同时设置多个category,一旦设置多个catrgory,
    那么每个category都必须能够和过滤条件中的某个category匹配成功.

    我们发现3中的规则和action的匹配规则有所不同,action有多个的时候,只要其中之一能够匹配成功即可,但是category必须是每一个都需要匹配成功,这个对比起来还是挺好记住的吧。那么按照这个规则的话,为了匹配示例中的过滤条件,我们可以这样设置category:intent.addCategory("com.leo.c");或者是intent.addCategory("com.leo.d");在或者是不设置category

    3.data的匹配规则

    在介绍data的匹配之前,我觉得还是有必要再温故一下data的结构吧

    <data android:scheme="string"
          android:host="string"
          android:port="80"
          android:path="/string"
          android:pathPattern="string"
          android:pathPrefix="/string"
          android:mimeType="text/plain"/>
    

    总的来说data包含两部分:mimeType和URI。

    1. mimeType表示image/ipeg,video/*等媒体类型
    2. URI信息量相对大一点,其结构一般为:
      <scheme>://<host>:<port>/[<path>|<pathPrefix|<pathPattern>>]

    下边讲分别来介绍下各个节点数据的含义

    1. scheme:整个URI的模式,如常见的http,file等,注意如果URI中没有指定的scheme,那么整个uri无效
    2. host:URI的域名,比如我们常见的www.mi.com,www.baidu.com,与scheme一样,一旦没有host那么整个URI也毫无意义;
    3. port:端口号,比如80,很容易理解,只有在URI中指定了scheme和host之后端口号才是有意义的;
    4. path,pathPattern,pathPrefix包含路径信息,path表示完整的路径,pathPattern在此基础上可以包含通配符,pathPrefix表示路径的前缀信息;

    ok,data的格式介绍完毕。

    其实data的匹配规则和action也有点类似:

    Intent中必须有data数据

    Intent中的data必须和过滤规则中的某一个data完全匹配

    过滤规则中可以有多个data存在,但是Intent中的data只需匹配其中的任意一个data即可

    过滤规则中可以没有指定URI,但是系统会赋予其默认值:content和file,这一点在Intent中需要注意

    为Intent设定data的时候必须要调用setDataAndType()方法,而不能先setData再setType,因为这两个方法是互斥的,都会清除对方的值,这个有兴趣可以参见源码

    在匹配规则中,data的scheme,host,port,path等属性可以写在同一个< />中,也可以分开单独写,其功效是一样的

    好了,说到这里,action,category和data的匹配规则基本都说完了,我们现在可以完全匹配一下文章开头的过滤条件示例了:

     Intent intent = new Intent("com.leo.a");
     intent.addCategory("com.leo.c");
     intent.setDataAndType(Uri.parse("file://abc"), "text/plain");
     startActivity(intent);
    
    4.匹配失败

    前边我们说到data的URI默认是content和file,所以如果你把intent.setDataAndType(Uri.parse("file://abc"), "text/plain");中的URI "file://abc"改为"http://abc"的话,就会出现以下异常


    其实包括action,category和data在内所有的匹配失败都会报这个异常,提示也很清晰明了。
    5.杜绝异常的发生

    为了避免发生以上异常,我们可以使用PackageManager或者Intent的resolveActivity()方法,,如果intent和过滤规则匹配失败,那么将返回null,我们也就不会再继续调用startActivity方法啦,从而去修改intent再次进行匹配直到成功匹配到预期intent。

    6.其他

    前文中也提到了在action和category中有一些是系统自带的,其中有些比较重要,比如

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

    这两者一般成双成对出现,用来表明这是一个程序的入口,并且会出现在系统的应用列表中。之所以成双成对的出现是说,二者缺一不可,少了彼此都没有实际意义。

    另外本文讲到的所有intent-filter匹配规则同样适用于Service和BroadcastReceiver,但是在Android5.0以后需要显式调用来启动Service,否则会报异常:java.lang.IllegalArgumentException: Service Intent must be explicit。

    扫码快速关注

    相关文章

      网友评论

      • __bc23:你这“action有多个的时候,只要其中之一能够匹配成功即可,但是category必须是每一个都需要匹配成功” 这句话写的是不是有问题 只需要匹配任意一个category就行
      • JimmieYang:没写引用出处真的好吗? 文字描述都和<<android开发艺术探索>>这本书上的基本一样:cold_sweat:
      • Yanqilong:“Intent中必须有data数据”, 这句话有问题吧,隐式启动 Activity 没有指定 data 也能启动活动

      本文标题:史上最全intent-filter匹配规则,没有之一

      本文链接:https://www.haomeiwen.com/subject/ucdarttx.html