增加 addDataScheme("file") 才能收到SD卡插拔事件的原因分析 -- 浅析android事件过滤策略

本文详细分析了Android中自定义BroadcastReceiver无法捕获SD卡插拔事件的问题,指出添加`filter.addDataScheme("file")`的重要性。通过示例程序,展示了事件(Intent)的分类、事件过滤策略、IntentFilter的使用。文章解释了SD卡插拔事件属于隐式事件,其action匹配但data部分需要通过URI匹配规则才能成功。添加`addDataScheme("file")`使得URI匹配成功,从而接收SD卡事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如有错漏请不吝拍砖指正,转载请注明出处,非常感谢

 


 

有一个问题,在网上被频繁的问到,就是为什么自定义的Receiver总是无法接收到SD卡插拔的事件。

而此问题大部分情况下可以通过增加一句代码解决: filter.addDataScheme("file");  // filter是IntentFilter对象

 

那么为什么增加这句代码就可以解决了呢?这个问题尽管有人问到,但是却没有太好的回答。

可能是因为对于精通IntentFilter策略的高手们来说,这根本算不上问题,是一个再明显不过的事实而已。

而对于不太了解IntentFilter策略的我们初学者来说,这个问题又暂时有点太难以理解吧。

 

因此,本文试着通过对android的事件过滤策略进行介绍和分析,结合示例程序进行验证,

来解答此问题,并浅显的介绍android事件过滤策略。

 


1. 编写示例程序,创建一个自定义的BroadcastReceiver

首先我们创建一个android工程起名为SdCardTester,作为示例程序。

为了方便在后续步骤中模拟SD卡插拔,建议将目标平台设定为2.3版本,使用2.3版本的模拟器。

此外务必注意,运行此示例程序的AVD模拟器需要增加SD卡功能支持。

 

然后为SdCardTester类增加一个BroadcastReceiver类型的成员变量 mReceiver。

在onCreate中,使用匿名类的技巧,为 mReceiver 赋值一个BroadcastReceiver子类实例。

注意代码中重写的onRecevie函数里只有一句代码,用于记录日志。以证明我们确实收到了事件。

 

然后创建一个IntentFilter,用于过滤SD卡插拔事件。

最后把我们自定义的Receiver和编写好的IntentFilter注册到系统中

 

最后的最后不要忘了在onDestory中注销我们的自定义Receiver,

至此完成了示例程序的代码编写,SdCardTester的完整代码如下:

### 实现 SD 拔插事件监听 为了实现在 Android 中监听 SD 的插入和移除操作,可以利用 `BroadcastReceiver` 来捕获特定的动作。当 SD 状态发生变化时,系统会发出相应的广播消息。 对于 SD 的状态变化,有两个重要的动作: - **Media Mounted (SD Card 插入)**: 动作字符串为 `"android.intent.action.MEDIA_MOUNTED"`。 - **Media Removed (SD Card 移除)**: 动作字符串为 `"android.intent.action.MEDIA_REMOVED"`。 下面是一个简单的例子来展示如何创建一个广播接收器用于监听这些事件[^1]。 #### 注册广播接收器 ##### 方式一:动态注册 这种方式适用于所有 API 版本,在应用运行期间有效。代码如下所示: ```java public class SDCardStateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if(Intent.ACTION_MEDIA_MOUNTED.equals(action)){ Toast.makeText(context,"SD card has been inserted.",Toast.LENGTH_SHORT).show(); }else if(Intent.ACTION_MEDIA_REMOVED.equals(action)){ Toast.makeText(context,"SD card has been removed.",Toast.LENGTH_SHORT).show(); } } } ``` 在 Activity 或 Service 中注册此接收器: ```java IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_MOUNTED); filter.addAction(Intent.ACTION_MEDIA_REMOVED); filter.addDataScheme("file"); registerReceiver(new SDCardStateReceiver(), filter); ``` 注意这里使用了 `addDataScheme()` 方法指定 scheme 为 "file", 这是因为从 Android N 开始对外部存储路径进行了调整[^2]. ##### 方式二:静态注册(仅限于某些情况) 由于安全性和性能考虑,Google 对静态注册广播施加了一些限制,特别是针对隐式意图。因此建议优先采用动态方式注册上述广播接收器。如果确实需要通过清单文件声明,则需要注意权限设置以及目标 SDK 的兼容性问题[^3]: ```xml <receiver android:name=".SDCardStateReceiver"> <intent-filter> <!-- 需要申请 READ_EXTERNAL_STORAGE 权限 --> <action android:name="android.intent.action.MEDIA_MOUNTED"/> <action android:name="android.intent.action.MEDIA_REMOVED"/> <data android:scheme="file"/> </intent-filter> </receiver> ``` 另外还需要确保应用程序拥有读取外部存储空间所需的权限 `<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>`.
评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值