zoukankan      html  css  js  c++  java
  • 简述 IntentFilter(意图过滤器)

    1.什么是IntentFilter ?

    IntentFilter翻译成中文就是“意图过滤器”,主要用来过滤隐式意图。当用户进行一项操作的时候,Android系统会根据配置的 “意图过滤器” 来寻找可以响应该操作的组件,服务。

    例如:当用户点击PDF文件的时候,Android系统就会通过设定好的意图过滤器,进行匹配测试。找到能够打开PDF文件的APP程序。

    代码:

    复制代码
    复制代码
     <activity android:name="com.example.testmain.ShowActivity" >
          <intent-filter>
                <action android:name="test.update.mydata" />
                <category android:name="my.test.show" />
                <data android:pathPattern=".*\.jpg" android:scheme="http" />
          </intent-filter>
     </activity>
    复制代码
    复制代码

    2.IntentFilter 如何过滤隐式意图?

    Android系统会根据我们配置的Intent Filter(意图过滤器),来进行匹配测试。匹配的时候,只会考虑三个方面:动作数据(URI以及数据类型)类别。也就是说Android系统会进行“动作测试”,“数据测试”,“类别测试”,来寻找可以响应隐式意图的组件或服务。

    另外,当对其他App程序开放组件和服务的时候也需要配置Intent Filter(意图过滤器),一个Activity可以配置多个<intent-filter>。

    3.动作测试:

    对应<intent-filter>中的<action/>标签;

    (1) 如果<intent-filter>标签中有多个<action/>,那么Intent请求的Action,只要匹配其中的一条<action/>就可以通过了这条<intent-filter>的动作测试。
     
    (2) 如果<intent-filter>中没有包含任何<action/>,那么无论什么Intent请求都无法和这条<intent-filter>匹配。
     
    (2) 如果Intent请求中没有设定Action(动作),那么这个Intent请求就将顺利地通过<intent-filter>的动作测试(前提是<intent-filter>中必须包含有<action/>,否则与第二条冲突)。
     
     
    4.类别测试:

    对应<intent-filter>中的<category />标签;

    (1)Intent中的类别必须全部匹配<intent-filter>中的<category />,但是<intent-filter>中多余的<category />将不会导致匹配失败。

    例如:Intent中有3个类别,而意图过滤器中定义了5个,如果Intent中的3个类别都与过滤器中的匹配,那么过滤器中的另外2个,将不会导致类别测试失败。

    注意:有一个例外,Android把所有传给startActivity()的隐式意图当作他们包含至少一个类别:"android.intent.category.DEFAULT" (CATEGORY_DEFAULT常量)。 因此,想要接收隐式意图的活动必须在它们的意图过滤器中包含"android.intent.category.DEFAULT"。(带"android.intent.action.MAIN"和"android.intent.category.LAUNCHER"设置的过滤器是例外)

    5.数据测试:

    对应<intent-filter>中的<data>标签;

    <data>元素指定了可以接受的Intent传过来的数据URI和数据类型,当一个意图对象中的URI被用来和一个过滤器中的URI比较时,比较的是URI的各个组成部分。

    例如:

    如果过滤器仅指定了一个scheme,所有该scheme的URIs都能够和这个过滤器相匹配;

    如果过滤器指定了一个scheme、主机名但没有路经部分,所有具有相同scheme和主机名的URIs都可以和这个过滤器相匹配,而不管它们的路经;

    如果过滤器指定了一个scheme、主机名和路经,只有具有相同scheme、主机名和路经的URIs才可以和这个过滤器相匹配。

    当然,一个过滤器中的路径规格可以包含通配符,这样只需要部分匹配即可。


    比较规则如下:

    (1) 一个既不包含URI也不包含数据类型的意图对象,仅在过滤器也同样没有指定任何URI和数据类型的情况下才能通过测试。

    (2)一个包含URI但没有数据类型的意图对象,仅在它的URI和一个同样没有指定数据类型的,过滤器里的URI匹配时才能通过测试。这通常发生在类似于mailto:和tel:这样的URIs上:它们并不引用实际数据。

    (3)一个包含数据类型但不包含URI的意图对象,仅在这个过滤器列举了同样的数据类型,而且也没有指定一个URI的情况下才能通过测试。

    (4)一个同时包含URI和数据类型(或者可从URI推断出数据类型)的意图对象可以通过测试,如果它的类型和过滤器中列举的类型相匹配的话。如果它的URI和这个过滤器中的一个URI相匹配或者它有一个内容

    content:或者文件file: URI,而且这个过滤器没有指定一个URI,那么它也能通过测试。换句话说,一个组件被假定为支持 ”content: 数据“ 和 “file: 数据”,如果它的过滤器仅列举了一个数据类型。

    例如AndroidManifest.xml中有:

    复制代码
    复制代码
    <intent-filter>
      <action android:name="com.nanlove.wangshiming"/>
      <action android:name="wangshiming"/>
      <category android:name="android.intent.category.DEFAULT" />
      <category android:name="wangshiming.intent.category"/>
      <data android:scheme="love" android:host="hao123.com" 
          android:port="888" android:path="/MM" android:mimeType="text/plain"/> </intent-filter>
    复制代码
    复制代码

    对于<intent-filter>中的action项可以有多个只要匹配其中一个就可以了

    intent.setAction("com.nanlove.wangshiming");//中的action也可以为wangshiming

    intent.addCategory("wangshiming.intent.category")代码中的addCategory并不用写因为android他有默认的category 只要配置清单中存在<category android:name="android.intent.category.DEFAULT" />就可以了.

    没有  "数据参数" 的情况下只要意图对象中的设置动作和类别都出现在intent-filter就能跟filter匹配,但是有数据<data android:scheme="love" android:host="hao123.com"  android:port="888" android:path="/MM" />数据项一定要完全匹配。

    当数据和数据类型 android:mimeType="text/plain"同时存在的时候,不能使用intent.setData(Uri.parse("love://hao123.com:888/MM")) ;

    因为setData的方法会自动清除前面的数据类型:This method automatically clears any type that was previously set by setType;

    所以后面的setType就无法匹配,应该使用intent.setDataAndType(Uri.parse("love://hao123.com:888/MM"), "text/plain");

    提示:在同一个应用内,能使用显示意图,就尽量使用显示意图,增加程序的效率,理论上隐式意图匹配规则是需要花时间寻找的。

      

    1 Intent分为两大类,显式和隐式。

    显式事件,就是指通过 component Name 属性,明确指定了目标组件的事件。

    比如我们新建一个Intent,指名道姓的说,此事件用于启动名为"com.silenceburn.XXXX”的Activity,那么这就是一个显式事件。

    隐式事件,就是指没有 component Name 属性,没有明确指定目标组件的事件。

    比如系统向所有监控通话情况的程序发送的“来电话了!”的事件,由于系统不确定谁会处理这个事件,因此系统不会明确指定目标组件,也就是说没有目标组件,那么这就是个隐式的事件。

    此处只是简介显式和隐式事件,更精确详细的描述请查阅SDK文档,我们只需要记住一点,两种事件的最大区别是 component Name 属性是否为空。

     

    2 事件过滤策略 和 IntentFilter

    系统在传送显式事件时非常方便,因为如果把Intent比作一封信,那么component Name就是一个详细的收件人地址,系统可以精确的把显式事件送达目标组件。

     

    而传送隐式事件时,就比较麻烦了。因为这封信的信封上,没有写收信地址!

    那怎么办呢?系统做了一个艰难的决定,就是把信拆开看看。通过信件内容里面的线索,去寻找合适的收件人。

    比如信中的线索描述到:“收信人是男性,快30岁了,未婚,喜欢玩游戏”,那么系统就在小区里面去找这样的人。

     

    非常值得庆幸的事情是,这个小区的人素质非常高,每户人家都写了点自我介绍在门口,

    比如张三写道:“我是男性,90后,未婚,喜欢玩游戏”,李四写道:“我是女性,快30岁了,未婚,喜欢逛街”等等等等。

    有了每户人家的自我介绍,系统就能很快的定位真正的收件人了!

     

    上面是一个类比的例子,不过android系统处理隐式事件的策略,基本上就是上述这种模式了。

     

    首先系统会通过观察Intent的内容(打开信件看内容),取得匹配线索,系统所需的线索是如下三种 :

     action

     data (both URI and data type)

     category

     

    其次,系统中每个组件,如果想收取隐式事件,则必须声明自己的IntentFilter(自我介绍,我对什么样的信件感兴趣)。

    至于怎么写IntentFilter,已经相当明了了,那就是应该是这样写:

    "我是组件XXXX,我想要接收这样的隐式事件:它的ACTION必须是 XXX,它的 category 必须是 YYYY ,它包含的data必须是ZZZZ "

    如果组件不声明IntentFilter,那么所有的隐式事件都不会发送给该组件。(注意,这并不影响向该组件发送显式事件。)

     

    对于系统中发生的每个隐式事件,系统都会尝试将 action, data , category 和系统中各个组件声明的IntentFilter 去进行匹配,以找到合适的接收者。

    3.IntentFilter匹配原则

    对于显式事件,系统可以精确送达。对于隐式事件,系统分析事件的 action, data , category 内容,并和各个组件声明的IntentFilter进行匹配,找出匹配的组件进行送达。action和category没什么好说的,再此我将最复杂的data匹配展开来进行描述一下:

    首先务必认识到,data是一个相对复杂的要素。

    data由URI来描述和定位,URI由三部分组成,

    scheme://host:port/path      模式://主机:端口/路径

    此外在事件中,还可以设置data的MIME类型,作为事件的datatype属性。为了描述方便,下文将IntentFilter简写为filter,请大家注意。

    首先明确一个匹配原则,就是对于URI的匹配,只比较filter中声明的部分。

    部分匹配原则:只要filter中声明的部分匹配成功,就认为整个URI匹配成功。

    举例来说,     content://com.silenceburn.SdCardTester:1000/mydata/private/

    filter定义为  content://com.silenceburn.SdCardTester:1000/     是可以匹配的。

    注意filter中并没有定义path部分,但是依然可以匹配成功,因为filter不声明的部分不进行比较。

    换句话讲,任何符合content://com.silenceburn.SdCardTester:1000/的事件,无论path是什么,都可以匹配成功。

    接下来是真正的data部分的,也就是URI的匹配规则如下:

    1. 如果data的URI和datatype为空,则 filter 的URI和type也必须为空,才能匹配成功

    2. 如果data的URI不为空,但是datatype为空,则 filter 必须定义URI并匹配成功,且type为空,才能匹配成功

    3. 如果data的URI为空,但是datatype不为空,则 filter 必须URI为空,定义type并匹配成功,才能匹配成功

    4. 如果data的URI和data都不为空,则 filter 的URI和type都必须定义并匹配成功,才能匹配成功。对于URI部分,有一个特殊处理,就是即使filter没有定义URI,content和file两种URI也作为既存的URI存在。

     

    通过上文的描述,大家就可以明白为什么在注册SD卡插拔接收器时,不但需要

    复制代码
    IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
    
                  intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
    
                  intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
    
                  intentFilter.addAction(Intent.ACTION_MEDIA_REMOVED);
    
                  intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
    
                  intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
    复制代码

    而且需要添加

        

       intentFilter.addDataScheme("file");

    注册应用安装卸载事件时不但需要

    复制代码
           IntentFilter intentFilter = new IntentFilter();
    
                  intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
    
                  intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    
                  intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    复制代码

    而且需要

           intentFilter.addDataScheme("package");

    原因就在Data的匹配。

  • 相关阅读:
    结合源码理解Spring MVC处理流程
    Spring Bean的生命周期分析
    面试官:给我说一下你项目中的单点登录是如何实现的?
    Java中的四种引用
    JWT实战总结
    Java读写锁的实现原理
    深入的聊聊Java NIO
    一线大厂Mysql面试题详解
    脱发、秃头防不胜防?这里有一份给码农的减压指南
    手把手教你提高代码Java运行的效率
  • 原文地址:https://www.cnblogs.com/Alex80/p/11862634.html
Copyright © 2011-2022 走看看