• IntentFilter的匹配原则


        1:概述

        我们知道启动Activity分为两种,显式调用和隐式调用。隐式调用需要Intent能够匹配目标组件的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。下面详细分析各种属性的匹配规则。

        2、action的匹配规则

         action是一个字符串,系统预定义了一些action,同时我们也可以在应用中定义自己的action。action的匹配是Intent中的action必须能够和过滤规则中的action匹配,这里说的匹配是指action的字符串值完全一样。一个过滤规则中可以有多个action,那么只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功(一个或者多个都行),action区分大小写,大小写不同会导致匹配失败。也就是说,如果intent-filter中如果存在action,那么Intent必须有action且不需和过滤规则中的其中一个action相同。

        3、category的匹配原则

        category是一个字符串,。category的匹配规则和action不同,它要求Intent中如果含有category,那么所有的category都必须和过滤规则中的其中给一个category相同,与action不同的是,intent中可以没用category,如果没有的话也可以匹配成功,同时,为了我们的activity能够接受隐式调用,就必须在intent-filter中添加“android.intent.category.DEFAULT”这个category。

    Action测试

    为了指定能够接收并处理的Intent的类型,组件可以在intent-filter中声明其支持0个或多个action,例如:

    <intent-filter>
        <action android:name="com.ispring.action.ACTION_TEST1" />
        <action android:name="com.ispring.action.ACTION_TEST2" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>

    intent对象可以通过setAction()方法设置唯一的一个action值。对于action测试,需要分两种情况:

    • intent对象设置了action 
      如果intent对象通过调用setAction()方法设置了action的值,那么只有当组件的intent-filter中包含了intent对象中的action值的时候,action测试才通过,否则无法通过。 
      举个例子,假设我们的Activity的intent-filter如下所示:

      <intent-filter>
         <action android:name="com.ispring.action.ACTION_TEST1" />
         <action android:name="com.ispring.action.ACTION_TEST2" />
         <category android:name="android.intent.category.DEFAULT" />
         <data android:scheme="ispring" android:host="blog.csdn.net" />
      </intent-filter>
      • 下面的intent对象可以通过上面intent-filter里面的action测试:

        Intent intent = new Intent();
        intent.setAction("com.ispring.action.ACTION_TEST1");
        Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");
        intent.setData(uri);

        该intent之所以能通过action测试是因为intent-filter中包含该intent的action值com.ispring.action.ACTION_TEST1。

      • 下面的intent对象无法通过上面intent-filter里面的action测试:

        Intent intent = new Intent();
        intent.setAction("com.ispring.action.ACTION_TEST3");
        Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");
        intent.setData(uri);

        该intent之所以无法通过action测试是因为intent-filter中不包含该intent的action值com.ispring.action.ACTION_TEST3。

    • intent对象没有设置action 
      如果intent对象没有调用setAction()方法设置action的值,那么如果intent-filter至少有一个任意的action的值,该intent对象就可以通过该intent-filter的action测试,反之,如果intent-filter中没有定义任何的action,那么该intent无法通过该intent-filter的action测试。 
      举个例子,假设我们的intent对象如下所示:

      Intent intent = new Intent();
      //不设置action值
      //intent.setAction("com.ispring.action.ACTION_TEST1");
      Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");
      intent.setData(uri);
      • 上面的intent对象可以通过如下的intent-filter:

        <intent-filter>
            <action android:name="com.csdn.action.ACTION_XXX" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="ispring" android:host="blog.csdn.net" />
        </intent-filter>
      • 上面的intent对象无法通过如下的intent-filter:

        <intent-filter>
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="ispring" android:host="blog.csdn.net" />
        </intent-filter>

      通过上面的几个示例,想必大家都已经理解了action测试的规则,至于上面的category和data标签的使用,会在下面详细介绍。

    总结起来有两点结论: 
    1. 要想让intent对象通过action测试,那么intent-filter中声明的action不能为空且要包含intent对象中的action值(如果intent的action值不为空的话)。 
    2. 如果intent-filter没有声明任何action,那么所有的intent的对象(即无论intent如何配置)都无法通过intent-filter的action测试。


    Category测试

    为了指定能够接收并处理的Intent的类型,组件可以在intent-filter中声明其支持0个或多个category,例如:

    <intent-filter>
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        ...
    </intent-filter>

    intent对象有addCategory()方法,也就是说一个intent对象也可以关联多个category。为了能让intent对象通过intent-filter的category测试,intent对象中的所有category都要在intent-filter中找到对应项。 
    具体来说,又分为如下两种情况:

    • intent对象至少有一个category 
      这种情况下,假设intent对象有N个category(N >=1),那么intent-filter中必须要包含这N个category,intent对象才能通过category测试,否则无法通过测试。如果用intent对象启动Activity,还有其他限制条件,会在后面详细说明。 
      举个例子,假设我们的intent-filter如下所示:

      <intent-filter>
          <action android:name="com.ispring.action.ACTION_TEST1" />
          <category android:name="android.intent.category.DEFAULT" />
          <category android:name="com.ispring.category.TEST1" />
          <category android:name="com.ispring.category.TEST2" />
      </intent-filter>
      • 以下intent对象能够通过category测试

        Intent intent = new Intent();
        intent.setAction("com.ispring.action.ACTION_TEST1");
        intent.addCategory("com.ispring.category.TEST1");
        intent.addCategory("com.ispring.category.TEST2");

        该intent对象之所以可以通过category测试是因为intent-filter包含了该intent对中所有的category值:com.ispring.category.TEST1”和com.ispring.category.TEST2。

      • 以下intent对象无法通过category测试

        Intent intent = new Intent();
        intent.setAction("com.ispring.action.ACTION_TEST1");
        intent.addCategory("com.ispring.category.TEST1");
        intent.addCategory("com.ispring.category.TEST3");

        该intent之所以无法通过上面的intent-filter的category测试是因为intent-filter只包含了该intent中值为com.ispring.category.TEST1的category,而并未包含值为com.ispring.category.TEST3的category,不满足完全包含intent中全部category的情况。

    • intent对象不包含任何category 
      如果intent对象没有调用过addCategory()方法,那么intent对象就不包含任何的category。这种情形下,如果该intent不是用来启动Activity的话,那么无论intent-filter中category中如何配置,intent对象总是能通过intent-filter的category测试,即便intent-filter中没有声明任何的category,intent都能通过category测试。此处强调了该intent不是用来启动Activity这种条件,会在下面详细解释。

    此处需要特别说明的是,我们在上面所有的示例中,都给Activity的intent-filter添加了值为android.intent.category.DEFAULT的category,这是因为当我们把一个隐式的intent传递给startActivity()startActivityForResult()方法时,Android会自动给该隐式intent添加值为android.intent.category.DEFAULT的category,所以为了能让intent-filter包含intent中全部的category,我们就需要在Activity的intent-filter中添加该category,在使用时需要特别注意。

    根据上面我们的几个示例,我们总结如下: 
    1. 如果intent对象不包含任何category,并且该intent不是用来启动Activity的,那么该intent对象总是能通过所有任意的intent-filter的category测试; 
    2. 如果intent对象包含category(至少一个),那么只有当intent-filter中声明的category全部包含intent对象中的所有category的时候才通过category测试。 
    3. 如果允许Activity被隐式的Intent启动,那么我们必须在该Activity的intent-filter中声明值为android.intent.category.DEFAULT的category。


    Data测试

    为了指定可以接收的Intent的data,intent-filter需要声明0个多多个<data />标签,例如:

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

    每个<data />标签都可以指定一个URI结构以及data的MIME类型。一个完整的URI由schemehostportpath组成,其结构如下所示:

    <scheme>://<host>:<port>/<path>

    其中scheme既可以是Android中常见的协议,也可以是我们自定义的协议。Android中常见的协议包括content协议、http协议、file协议等,自定义协议可以使用自定义的字符串。

    • 如下是一个content协议的URI: 
      content://com.example.project:200/folder/subfolder/etc 
      在该URI中,scheme是content,host是com.example.project,port是200,path是folder/subfolder/etc。

    • 如下是一个自定义协议的URI: 
      ispring://blog.csdn.net/sunqunsunqun 
      在该URI中,scheme是ispring,host是blog.csdn.net,没有明确设定port,path是sunqunsunqun。

    组成URI的这些属性在<data />标签中都是可选的 ,但存在如下的依赖关系:

    • 如果没有指定scheme,那么host参数会被忽略
    • 如果没有指定host,那么port参数会被忽略
    • 如果scheme和host都没有指定,path参数会被忽略

    当我们将intent对象中的Uri参数与intent-filter中的<data />标签指定的URI格式进行对别时,我们我们只对比intent-filter的<data />标签指定的部分,例如:

    • 如果intent-filter中只指定了scheme,那么所有带有该sheme的URI都能匹配到该intent-filter。
    • 如果intent-filter中只指定了scheme和authority(authority包括host和port两部分)而没有指定path,那么所有具有相同scheme和authority的URI都能匹配到该intent-filter,而不用考虑path为何值。
    • 如果intent-filter中同时指定了scheme、authority和path,那么只有具有相同scheme、authority和path的URI才能匹配到该intent-filter。

    需要注意的是,intent-filter的<data />标签在指定path的值时,可以在里面使用通配符*,起到部分匹配的效果。

    data测试需要同时将intent对象中的URI、MIME类型与intent-filter的<data />标签中指定的URI、MIME类型进行对比。 
    我们知道一个intent-filter下可以有多个<data />标签,intent对象无需通过所有的<data />标签测试,一般情况下,我们的intent对象只需通过了其中一个<data />标签的测试并满足某些特定情形下的一些条件,那么该intent对象就通过了该intent-filter的data测试。 
    进行对比的规则分以下几种情况:

    • intent对象不包含URI和MIME类型 
      这种情况下,只有当intent-filter也没有指定任何URI和MIME类型的时候才能通过data测试。 
      例如我们有如下intent对象:

      Intent intent = new Intent();
      intent.setAction("com.ispring.action.ACTION_TEST1");
      • 上面的intent对象可以通过下面的intent-filter的data测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
      • 上面的intent对象无法通过下面的intent-filter测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="ispring" />
        </intent-filter>
    • intent对象包含URI但不包含MIME类型 
      这种情况下,只有当intent对象的URI匹配到了intent-filter中的URI格式,并且intent-filter没有指定MIME类型的时候才能通过data测试。需要注意的是,这里所说的intent-filter没有指定MIME类型的情形指的是intent-filter中所有的<data />标签都没有指定MIME类型,即整个intent-filter中完全没有android:mimeType这几个字,理解这点很重要,大家在下面的几个示例中可以体会到这点。 
      例如有如下intent对象:

      Intent intent = new Intent();
      intent.setAction("com.ispring.action.ACTION_TEST1");
      Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");
      intent.setData(uri);
      • 上面的intent能通过如下的intent-filter的data测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="ispring" android:host="blog.csdn.net" />
        </intent-filter>
      • 上面的intent对象可以通过以下intent-filter的data测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="ispring" android:host="blog.csdn.net" />
            <data android:scheme="sunqun" android:host="8080" />
        </intent-filter>

        intent对象虽然不能通过scheme为sunqun的<data />标签测试,但是可以通过scheme为ispring的data标签测试,且intent对象和intent-filter中的两个<data />标签都没有指定MIME,所以上面的intent对象可以通过该intent-filter测试。

      • 上面的intent对象无法通过以下intent-filter的<data />标签测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" android:scheme="ispring" android:host="blog.csdn.net" />
        </intent-filter>

        上面的intent对象之所以不能通过intent-filter中唯一的一个<data />标签测试是因为我们的intent对象没有指定MIME类型,但是上面的<data />标签通过android:mimeType="text/plain"设置了MIME类型。

      • 上面的intent对象无法通过以下intent-filter的data测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="ispring" android:host="blog.csdn.net" />
            <data android:mimeType="text/plain" />
        </intent-filter>

        上面的intent对象之所以无法通过该intent-filter中的data测试,是因为intent对象没有设置MIME类型,但是intent-filter中第二个data标签通过android:mimeType="text/plain"设置了MIME类型。

    • intent对象包含MIME类型但不包含URI 
      这种情况下,只有当intent中的MIME类型与intent-filter中列出的MIME类型相同,并且intent-filter没有指定任何的URI格式的时候才能通过data测试。需要注意的是,这里所说的intent-filter没有指定任何的URI格式的情形指的是intent-filter中所有<data />标签都没有指定URI,即整个intent-filter中完全没有android:schemeandroid:hostandroid:port以及android:path,理解这点很重要,大家在下面的几个示例中可以体会到这点。 
      例如有如下intent对象:

      Intent intent = new Intent();
      intent.setAction("com.ispring.action.ACTION_TEST1");
      intent.setType("text/plain");
      • 上面的intent对象可以通过以下intent-filter的data测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
      • 上面的intent对象可以通过下面的intent-filter的data测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="image/*" />
            <data android:mimeType="text/plain" />
        </intent-filter>

        上面的intent对象虽然没有通过MIME类型为image/*的第一个data标签测试,但能通过第二个data标签测试,并且intent对象和intent-filter都没有指定任何的URI格式。

      • 上面的intent对象不能通过以下intent-filter中的data测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" android:scheme="ispring" />
        </intent-filter>

        上面的intent对象中没有设置URI信息,但是在该intent-filter中设置了URI中的scheme值,所以intent无法通过intent-filter的data测试。

      • 上面的intent对象无法通过以下intent-filter中的data测试:

        <intent-filter>
            <action android:name="com.ispring.action.ACTION_TEST1" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain"  />
            <data android:scheme="ispring" />
        </intent-filter>

        上面的intent对象没有指定URI信息,但是上面的intent-filter中第二个<data />标签设置了URI中的scheme信息,所以intent对象无法通过该intent-filter的data测试。

    • intent对象同时包含URI和MIME类型 
      这种情况下,要分别测试URI以及MIME类型测试是否通过,只有URI以及MIME测试都通过了,data测试才能通过。

      • 对于MIME测试:如果intent的MIME类型能够匹配intent-filter中列出的某一个<data />标签中的MIME类型值,那么MIME类型测试就通过了。
      • 对于URI测试: 
        又细分两种情况,满足下面的任何一种情况都可以通过URI测试。 
        • 如果intent的URI格式能够匹配intent-filter中列出的某一个<data />中的URI,那么URI测试就通过了。
        • 如果intent的URI是content:协议或file:协议,并且整个intent-filter的所有<data />标签中都没有指定URI,那么该intent也能通过URI测试。换句话说,如果一个intent-filter只列出了MIME类型,没有列出任何URI相关的格式的话,那么这个intent-filter就默认是支持content:协议或file:协议的。

      下面举几个例子大家自己体会一下。

      • 假设有如下协议为自定义协议ispring:的intent对象:

        Intent intent = new Intent();
        intent.setAction("com.ispring.action.ACTION_TEST1");
        Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");
        String type = "text/plain";
        intent.setDataAndType(uri, type);
        • 上面的intent对象可以通过下面的intent-filter的data测试:

          <intent-filter>
                <action android:name="com.ispring.action.ACTION_TEST1" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="ispring" android:host="blog.csdn.net" />
                <data android:mimeType="text/plain"  />
          </intent-filter>
        • 上面的intent对象无法通过下面的intent-filter的data测试:

          <intent-filter>
                <action android:name="com.ispring.action.ACTION_TEST1" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="ispring" android:host="blog.csdn.net" android:port="8080" />
                <data android:mimeType="text/plain"  />
          </intent-filter>

          port不满足,URI测试不通过,导致data测试失败。

        • 上面的intent对象无法通过下面的intent-filter的data测试:

          <intent-filter>
                <action android:name="com.ispring.action.ACTION_TEST1" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="ispring" android:host="blog.csdn.net" />
                <data android:mimeType="image/*"  />
          </intent-filter>

          android:mimeType不满足,MIME类型测试不通过,导致data测试失败。

      • 假设有如下协议为content:的intent对象:

        Intent intent = new Intent();
        intent.setAction("com.ispring.action.ACTION_TEST1");
        Uri uri = Uri.parse("content://com.ispring.test");
        String type = "text/plain";
        intent.setDataAndType(uri, type);
        • 上面的intent对象无法通过下面的intent-filter的data测试:

          <intent-filter>
                <action android:name="com.ispring.action.ACTION_TEST1" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="ispring" />
                <data android:mimeType="text/plain"  />
          </intent-filter>

          URI中的scheme不匹配,导致URI测试不通过,导致data测试失败。

        • 上面的intent对象可以通过下面的intent-filter的data测试:

          <intent-filter>
                <action android:name="com.ispring.action.ACTION_TEST1" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain"  />
          </intent-filter>

          intent中使用的是content:协议,并且整个intent-filter中都没有定义URI格式,所以URI测试是可以通过的,并且MIME类型能找到匹配项,所以可以通过data测试。


  • 相关阅读:
    HDU 4611 Balls Rearrangement 数学
    Educational Codeforces Round 11 D. Number of Parallelograms 暴力
    Knockout.Js官网学习(简介)
    Entity Framework 关系约束配置
    Entity Framework Fluent API
    Entity Framework DataAnnotations
    Entity Framework 系统约定配置
    Entity Framework 自动生成CodeFirst代码
    Entity Framework CodeFirst数据迁移
    Entity Framework CodeFirst尝试
  • 原文地址:https://www.cnblogs.com/vegetate/p/9997306.html
Copyright © 2020-2023  润新知