Android: 关于存储设备状态改变的静态广播无法接收的问题
一. 问题描述:
最近在重构存储设备功能模块,想要将原本的动态广播转换为静态广播,这样不管在哪个地方,存储设备状态改变,我都能收到提示。于是我尝试了以下代码:
1 | <receiver |
但是如论如何,都接收不到该广播。
起初以为是自己的java
文件有毛病,但是手动发送一个广播,又能成功接收到。
所以具体是什么原因呢? 首先我按照 “静态广播无法接收” 的关键词 google 了一下,查到的全是静态广播如何写这样的文章,我….
二. 解决办法
过了几天,突发奇想,按照“INTENT.ACTION_MEDIA_MOUNTED” 这个关键词直接 google,找了一圈,发现 一篇文章 里有解决办法,如下:
1 | <receiver |
所以为什么要添加这一行呢,参考链接里也贴了 详解的链接 ,接下来,我就再复习一遍吧。
三. 关于 Andoroid 事件过滤策略
Intent 的分类:显式和隐式
一个 Intent 包含的信息
图片取自 Intent详解 该文章有对 Intent
进行较为详细的解释,需要的战友可以进去看看。
由图可以看到,显式 Intent
与隐式 Intent
最大的区别,是 ComponentName
是否为空。
2. 事件过滤策略与 IntentFilter
原链接 的比喻挺适合理解。我就用自己的话再复述一遍吧:将系统广播的分发比喻为信件的派发。当信件上有收件人的详细地址时,邮递员可以直接通过地址找到你,并将信件放到你的手上。那如果,信件上没有详细地址,只有收件人的特征—— 男,30岁,码农。这样的信件邮递员该如何处理呢?邮递员惊喜地发现,负责信件派发区域内的所有房门上都有住户的特征介绍,比如:女,20岁,学生; 女,35岁,家庭主妇… 如此一来,只要对应上 所有 特征,就把信件交付给相应地住户就 OK 了。
当然这是不恰当地比喻,因为信件只有一封,只能给到一个人。但是系统可以将事件分发给所有符合条件的程序。
这个比喻里,有详细地址的信件,就相当于 Intent.getComponent != null
系统可以通过ComponentName
直接找到接收此事件的组件。而没有指定Intent.Component
的事件,就只能借助其它特征来决定该给哪些程序发广播了,这些特征就是Action
、Data
、Category
当程序给出的所有接收特征与系统广播的这些特征一一对应,那么就能接收到相应的广播啦。
那么我们就来研究下,在 SD 卡发生插拔事件时,系统发出的广播都携带了哪些特征叭!
- 动态注册广播:
1 | IntentFilter filter = new IntentFilter(); |
- 打印信息
1 | private BroadcastReceiver myStorageReceiver = new BroadcastReceiver() { |
- 打印结果
可以看到,componentName
为 空,为隐式事件。
由图可以看到,IntentFilter
可以添加如上特征进行事件过滤,必须全部匹配才能收到事件广播。
3. Data 匹配规则
Data
由 Uri
来描述,而Uri
由三部分组成:
==scheme://host:port/path== | 模式://端口:主机号/路径
从打印结果可以看到,SD 挂载事件,data: scheme == "file"
现在我们需要了解一个规则,即对于Uri
,只比较filter
中声明的部分,如果匹配到声明的部分,即认为匹配成功。
我们代码中只声明了scheme
部分,并且与Uri
成功匹配,所以匹配成功。
Uri
的具体匹配规则如下:
- 如果
data
的Uri
与dataType
均为空,那么filter
中也需要全部为空才能匹配成功 - 如果
data
的Uri
为空,dataType
不为空,那么filter
中的Uri
必须为空,且dataType
匹配成功,才能匹配成功 - 如果
data
的Uri
不为空,dataType
为空,那么filter
中的Uri
必须匹配成功,且dataType
为空,才能匹配成功 - 如果
data
的Uri
与dataType
均不为空,那么filter
中必须定义两者并且都匹配成功,才能匹配成功
一句话总结,即IntentFilter
必须与Intent
携带信息全部匹配成功,才能接收事件。
四. 最后
还是看看 原链接 吧,讲得真的很好了。小菜鸡的语言组织能力还是太差了,今后继续加油。
留下疑问:既然data
的Uri
认为部分匹配成功,即认为匹配成功。那么我filter
中不添加scheme
,只添加path
匹配成功也收不到广播的问题在哪?