`
meohao
  • 浏览: 97814 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

写在20110904:Intent-filter

 
阅读更多
   为什么自定义的Receiver总是无法接收到SD卡插拔的事件。检查注册SD卡插拔事件是否有这句话 filter.addDataScheme("file");  // filter是IntentFilter对象,那么为什么有这句代码就可以解决了呢?

了解一下android的Intent-filter是如何接收来自外部的广播的。
1. 编写示例程序,创建一个自定义的BroadcastReceiver
首先我们创建一个android工程起名为SdCardTester,作为示例程序。
为SdCardTester类注册一个BroadcastReceiver类型的成员变量 mReceiver。
在onCreate中,使用匿名类的技巧,为 mReceiver 赋值一个BroadcastReceiver子类实例。
mReceiver = new BroadcastReceiver() { 
   @Override 
   public void onReceive(Context context, Intent intent) { 
       Log.i("myLoger"," Receive SDCard Mount/UnMount!"); 
   } 
}
    注意代码中重写的onRecevie函数里只有一句代码,用于记录日志。以证明我们确实收到了事件。然后创建一个IntentFilter,用于过滤SD卡插拔事件。最后把我们自定义的Receiver和编写好的IntentFilter注册到系统中
IntentFilter filter = new IntentFilter(); 
filter.addAction(Intent.ACTION_MEDIA_MOUNTED); 
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); 
registerReceiver(mReceiver, filter);  
最后的最后不要忘了在onDestory中注销我们的自定义Receiver,
unregisterReceiver(mReceiver);  

2. 测试示例程序
    运行SdCardTester,等看到hello World 字样,说明onCreate完成,也就意味着我们自定义的Receiver也已经启动了。之后,不要用BACK退出,按HOME按钮返回主屏幕,(也就是要保证我们的自定义Receiver仍然在运行)注意,按照我们当前的代码实现,无论我们如何插拔SD卡,都不会看到日志窗口监控到事件发生。
   增加那行代码:filter.addDataScheme("file");修改完成再次运行程序,不要BACK退出,按HOME按钮返回主屏幕,进入Setting模拟SD卡插拔,然后观察logCat日志监控窗口,可以接收到事件了!

3.事件(Intent)的分类:显式和隐式。那么,为什么加上 filter.addDataScheme("file"); 就可以了呢?
    为了解决这个问题,我们要先学习Intent的分类。Intent分为两大类,显式和隐式。显式事件,就是指通过Component Name 属性,明确指定了目标组件的事件。比如我们新建一个Intent,指名道姓的说,此事件用于启动名为"com.test.XXXX”的Activity,那么这就是一个显式事件。隐式事件,就是指没有 component Name 属性,没有明确指定目标组件的事件。比如系统向所有监控通话情况的程序发送的“来电话了!”的事件,由于系统不确定谁会处理这个事件,因此系统不会明确指定目标组件,也就是说没有目标组件,那么这就是个隐式的事件。此处只是简介显式和隐式事件,更精确详细的描述请查阅SDK文档,我们只需要记住一点,两种事件的最大区别是Component Name 属性是否为空。
 
4.事件过滤策略 和 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 去进行匹配,
以找到合适的接收者。
    上述是android系统的事件过滤策略的简单原理,实际情况远比这要复杂,考虑本文的目的,此处不再展开,SDK文档中都有详尽描述。

5. 分析SD卡插拔事件
由上节可知,对于显式事件,系统可以精确送达。对于隐式事件,系统分析事件的 action, data , category 内容,
并和各个组件声明的IntentFilter进行匹配,找出匹配的组件进行送达。

因此SD卡插拔事件能否被我们自定义的Recevier收到就取决于如下子问题了:
5.1. SD卡插拔事件是显式事件,还是隐式事件
5.2. SD卡插拔事件的action, data , category 的内容是什么
5.3. 我们自定义的Receiver组件的IntentFilter是如何声明的
   在onReceive()中添加详细的日志输出intent携带的相关信息,通过日志输出我们可以得知挂载SD卡事件的 Componet 是null ,因此它是一个隐式事件。因此能否送达,需要看事件的 action, data , category 和 IntentFilter是否匹配。
   它的ACTION是 android.intent.action.MEDIA_MOUNTED,和我们定义的IntentFilter的 filter.addAction(Intent.ACTION_MEDIA_MOUNTED); 语句相匹配。因此action部分是匹配的。
   它的Categories是null,而我们定义的 IntentFilter 也没有使用addCategory方法增加category定义,null ==  null,因此 categories也是匹配的。
   action, data , category 中的两个要素已经匹配,那么能否匹配成功的关键,就是看data是否匹配了。

6.data匹配规则
    首先务必认识到,data是一个相对复杂的要素。 data由URI来描述和定位,URI由三部分组成,scheme://host:port/path  模式://主机:端口/路径
例如我们截获的挂载SD卡事件,它的data的URI是 file:///mnt/sdcard
其中模式部分是 file , 主机:端口部分是空的, path部分是 mnt/sdcard
此外在事件中,还可以设置data的MIME类型,作为事件的datatype属性。
综上所述,data是一个较复杂的要素,因此其匹配规则也格外复杂,首先明确一个匹配原则,就是对于URI的匹配,只比较filter中声明的部分。部分匹配原则:只要filter中声明的部分匹配成功,就认为整个URI匹配成功。
举例来说,content://com.test.SdCardTester:1000/mydata/private/和filter定义为content://com.test.SdCardTester:1000/是可以匹配的。注意filter中并没有定义path部分,但是依然可以匹配成功,因为filter不声明的部分不进行比较。换句话讲,任何符合content://com.silenceburn.SdCardTester:1000/的事件,无论path是什么,都可以匹配成功。
接下来是真正的data部分的,也就是URI的匹配规则如下:
6.1. 如果data的URI和datatype为空,则 filter 的URI和type也必须为空,才能匹配成功
6.2. 如果data的URI不为空,但是datatype为空,则 filter 必须定义URI并匹配成功,且type为空,才能匹配成功
6.3. 如果data的URI为空,但是datatype不为空,则 filter 必须URI为空,定义type并匹配成功,才能匹配成功
6.4. 如果data的URI和data都不为空,则 filter 的URI和type都必须定义并匹配成功,才能匹配成功。
    对于URI部分,有一个特殊处理,就是即使filter没有定义URI,content和file两种URI也作为既存的URI存在。(举个例子,对于 content 和 file 两种模式的data,只要filter定义的datatype可以和事件匹配,就认为匹配成功,filter不需要显式的增加 content 和 file 两种模式,这两种模式内置支持 )有了规则,有了对SD卡插拔事件的内容的分析,我们就可以按图索骥照章办事了。

7.SD卡插拔事件的匹配
   首先如第6节所述,SD卡插拔是一个隐式事件,而且 action 和 category 部分和我们的 filter 均可以匹配成功。
其data部分的URI为 file:///mnt/sdcard ,datatype为 null ,因此应用第6节比较规则中的 2 号规则:
    2. 如果data的URI不为空,但是datatype为空,则 filter 必须定义URI并匹配成功,且type为空,才能匹配成功

我们的filter中没有使用 addtype 方法 ,因此 filter 的type为空, datatype部分匹配成功。
data的URI为file:///mnt/sdcard ,我们使用 filter.addDataScheme("file"); 语句定义 schema 为 file,
根据部分匹配规则,data匹配成功。

至此,整个事件匹配成功,至此,我们就明白了文初的问题,为什么必须添加  filter.addDataScheme("file"); 语句才能收到事件!我们可以尝试把 filter.addDataScheme("file"); 后面增加语句
filter.addDataPath("mnt/sdcard", PatternMatcher.PATTERN_LITERAL); 
依然可以匹配成功,收到SD卡插拔事件。因为这样就组成了一个URI的完全匹配。
我们可以尝试把给 filter 增加 datatype 属性,
try {
    filter.addDataType("text/*"); 
} catch (MalformedMimeTypeException e) { 
    e.printStackTrace(); 

这样就无法匹配成功了。因为SD卡插拔事件的datatype是null,
而我们定义的filter的datatype是MIME"text/*" 。
分享到:
评论

相关推荐

    Data、Type属性与Intent-filter配置

    在给定的标题“Data、Type属性与Intent-filter配置”中,我们关注的重点是如何通过设置`data`和`type`属性来过滤Intent,以便指定的应用组件(如Activity)能够响应特定的用户操作或系统事件。 `data`属性在Intent-...

    android intent and intent-filters

    - 在AndroidManifest.xml中,每个组件都可以定义一个或多个Intent-filter,用来声明该组件能处理哪些类型的Intent。 - 每个Intent-filter包含Action、Data和Category等元素。 2. Intent-filter匹配规则: - 一个...

    Activity_intent-filter

    当我们说到 "Activity_intent-filter" 时,我们实际上是在讨论如何通过设置 `intent-filter` 来使一个 `Activity` 对特定的 `Intent` 响应。 `Intent` 是Android中的一个消息传递对象,用于在组件之间传递请求或...

    IntentIntent-Filter思维导图

    IntentIntent-Filter思维导图

    Android Intent Filter用法

    在Android应用开发中,Intent Filter是一个至关重要的概念,它用于定义一个组件(如Activity或BroadcastReceiver)能够响应的Intent类型。Intent Filter就像一个过滤器,筛选出应用可以处理的特定操作,使得系统能够...

    intent匹配规则大总结

    在Android开发中,Intent作为组件间通信的重要工具,其匹配规则对于实现组件间的正确交互至关重要。本文将围绕给定文件提供的信息,深入解析Intent匹配规则的关键点,并结合具体示例帮助理解。 #### 一、Intent与...

    intent-action-send.7z

    在Android系统中,Intent是一种非常重要的组件间通信机制,它用于启动其他应用程序组件或传递数据。"intent-action-send"这个主题通常与发送数据到其他应用的功能相关,比如分享文本、图片或者文件。在这个场景下,...

    'com.android.support:appcompat-v7:28.0.0'的一个运行例子

    <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> ``` 然后,在`MainActivity.java`中,我们需要...

    Android Studio 实验二:Intent的使用

    在AndroidManifest.xml中,为组件定义Intent Filter,使得组件可以响应隐式Intent: ```xml <activity android:name=".MyActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> ...

    android中隐式intent与activity的匹配原则2022优秀文档.pptx

    在<intent-filter>标签中,至少应该包含一个&action子标签,否则任何Intent请求都不能和该<intent-filter>匹配。如果Intent请求的Action和<intent-filter>中的任意一个&action子标签匹配,那么该Intent就可以激活该...

    android基础随手笔记

    2>intent-filter中可以声明多个action <intent-filter> </intent-filter> 3>如果intent中的action是Intent-filter中 声明的action中的一个,则action匹配成功。 4>如果intent-filter中没有声明任何的action,...

    Android Intent 、intent-filter详解

    参考...,讲解的很好 1.什么是Intent(定义) Intent这个单词的意思就是”意图,目的,意向”,Intent是一种运行时绑定(runtime binding)机制,它能在程序运行的过程中连接两个不同的组件。 个

    ImagesWidget.rar

    <intent-filter> android:name="android.intent.action.MAIN" /> android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> android:name="android.appwidget.action.APP...

    android Intent的用法

    在Android开发中,Intent是一种非常重要的组件间通信机制。它被用来启动活动(Activity)、服务(Service)或者广播接收器(Broadcast Receiver),并且可以传递数据和执行动作。本篇文章将详细解析Intent的用法。 ...

    Checking_Intent-based_Communication_in_Android_With_Intent_Space_Analysis.pdf

    系统内部的security extensions包括:Intent Filter,Intent Firewall(可在系统路径/data/system/ifw/*.xml下查看,会记录哪些APP发送的怎样的intent会被block),Permissions,Protected Broadcasts(某些系统广播只能由...

    Androidmanifest.xml文件分析

    <intent-filter></intent-filter> <meta-data/> </activity-alias> <intent-filter></intent-filter> <meta-data/> <intent-filter></intent-filter> <meta-data/> <grant-uri-permission/> ...

    Intent filter 关于Action、Category属性详解源码

    Intent filter 关于Action、Category属性详解源码 对应的博客文章链接: http://blog.csdn.net/a13429921973/article/details/9271973

    Android解析Intent Filter的方法

    在Android应用开发中,Intent Filter是一种机制,用于让系统知道哪些组件(如Activity、Service等)能够处理特定类型的Intent。Intent Filter定义在AndroidManifest.xml文件中,允许开发者声明组件能够响应的动作...

Global site tag (gtag.js) - Google Analytics