Service: 监听外部存储设备
来源:互联网 发布:空铁列车 知乎 编辑:程序博客网 时间:2024/05/08 09:39
CodingMan
--- what is most important?
Service: 监听外部存储设备
博客声明:
1. 使用 android2.1 源码说明问题
2. 使用真机,操作系统是 android-2.1
3. 分享一下学习方法,不是为了测试而测试,请大家举一反三
结合 Service 与 Broadcast 监听外部存储设备的状态,通过测试主要想知道在我们操作外部存储设备时候发生了哪些事情、以及 Intent 几个 Action 到底是何意?
测试代码见 附录,至于如何启动这个 Service,随您意!
主要的 Action
注册这 13 个 action,然后运行 app ,点击 back 服务退至后台。
now,ready!来操作 sdcard。
1. 直接拔掉 sdcard
2. 再次将 sdcard 插入卡槽
先大概 1-3 秒的 media checking,然后才是 mounted -- scanner started -- scanner finished
3. 在通知栏卸载 sdcard
紧接着,从卡槽拔出 sdcard(必须拔出,才会接收到下面的 action)
可以看出,这种情况属于正常卸载 sdcard,不是强制拔出。不同于 1.
这个时候,你将 sdcard 插入卡槽,发生的情况与 2 一致。
4. 在通知栏选择 "计算机与 sd 卡之间复制文件",即共享
在弹出的对话框选择 "装载"
然后,我们再次在通知栏选择 "关闭 usb 存储设备",接下来发生的与 2 一致。
从这几个测试,我们可以发现几个规律:
1. 不管以何种方式卸载(正常卸载拔出、正常卸载不拔出 sd 卡、直接拔出 sd 卡)
系统都会发出下面的 action 广播
ACTION_MEDIA_EJECT
ACTION_MEDIA_UNMOUNTED
2. 不管以何种方式安装 sd 卡,系统都会发出下面的 action 广播
3. ACTION_MEDIA_REMOVED 与 ACTION_MEDIA_UNMOUNTED 区别
ACTION_MEDIA_REMOVED
表示 sdcard 已经从卡槽移除。
ACTION_MEDIA_UNMOUNTED
只可以说明 sd 卡没有 mount 在文件系统上面,不可以说明其已经从卡槽移除。
从测试 4 就可以看出这个端倪。
4. ACTION_MEDIA_REMOVED 与 ACTION_MEDIA_BAD_REMOVAL 区别
ACTION_MEDIA_BAD_REMOVAL
只有在直接拔出 sd 卡时,系统才会发送这样的 action 广播。
ACTION_MEDIA_REMOVED
不管何种方式从卡槽拔出 sd 卡时,系统就会发送这样的 action 广播。
5. 选择通过 usb 共享,系统一定会发出下面的 action 广播
ACTION_MEDIA_SHARED
ok,明白上面的道理(你基于的开发平台是否是这样,你还需要测试,我这里只是抛砖引玉),可以在接收到这些广播的时候,根据 action 写自己的逻辑代码了。如:
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_MEDIA_EJECT.equals(action)) {
- // 本人感觉 ACTION_MEDIA_EJECT 比
- // ACTION_MEDIA_UNMOUNTED 好
- // sd 卡不可用
- } else if (Intent.ACTION_MEDIA_REMOVED.equals(action)) {
- // sd 卡已经被移除卡槽
- } else if (Intent.ACTION_MEDIA_SHARED.equals(action)) {
- // 选择通过 usb 共享
- } else if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {
- // sd 卡可用
- }
- }
但是这里提醒一下:
接收到 ACTION_MEDIA_EJECT 广播之后,sd 卡还是可以读写的,
直到接收到 ACTION_MEDIA_REMOVED、ACTION_MEDIA_UNMOUNTED等广播之后,sd 卡才不可以读写。
可以借助 Music 源码 MediaPlaybackService.java 看看:
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
- saveQueue(true);
- mQueueIsSaveable = false;
- closeExternalStorageFiles(intent.getData().getPath());
- } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
- mMediaMountedCount++;
- mCardId = MusicUtils.getCardId(MediaPlaybackService.this);
- reloadQueue();
- mQueueIsSaveable = true;
- notifyChange(QUEUE_CHANGED);
- notifyChange(META_CHANGED);
- }
- }
到这个时候,我们应该搞明白是系统哪个类发出这样的广播?有没有新的发现?
android2.1/frameworks/base/services/java/com/android/server/MountService.java
与其相关的类是
android2.1/frameworks/base/services/java/com/android/server/MountListener.java
继续跟踪 MountService.java , 我们会发现实例化 intent:
intent = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
都包含一个 scheme 为 file 的 path,那麽这个 path 是什么呢?
可以在 onReceive 方法里面得到这个值
final String path = intent.getData().getPath()
其实,就是 "/sdcard" (即 sd 卡路径)。
这个信息很有用!!!
比如你的手机可以外括除了 sd 卡的其它外部设备(如 u 盘、map 卡)
那麽这个返回的路径就不一样,可以根据返回的路径判断你当前操作的是哪个设备了!
耶耶,酷比嘞!
在 MountService.java 里面还有一个与众不同的地方:
- void notifyMediaMounted(String path, boolean readOnly) {
- setMediaStorageNotification(0, 0, 0, false, false, null);
- updateUsbMassStorageNotification(false, false);
- Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,
- Uri.parse("file://" + path));
- intent.putExtra("read-only", readOnly);
- mMounted = true;
- mContext.sendBroadcast(intent);
- }
intent.putExtra("read-only", readOnly)
其中 readOnly 是一个 boolean 值,在 onReceive 里面 只有 action 是 ACTION_MEDIA_MOUNTED,接收到该值是 false.
------------- 附录
PlayerService.java
- package mark.zhang;
- import android.app.Service;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.os.IBinder;
- import android.util.Log;
- public class PlayerService extends Service {
- private static final String TAG = "PlayerService";
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public void onCreate() {
- super.onCreate();
- registerReceivers();
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- return super.onStartCommand(intent, flags, startId);
- }
- @Override
- public void onDestroy() {
- Log.d(TAG, "onDestroy------");
- super.onDestroy();
- unregisterReceivers();
- }
- private BroadcastReceiver externalStorageReceiver = null;
- /**
- * 注册广播
- */
- private void registerReceivers() {
- if (externalStorageReceiver == null) {
- externalStorageReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final String path = intent.getData().getPath();
- Log.d(TAG, "receive action = " + action);
- boolean value = intent.getBooleanExtra("read-only", true);
- Log.d(TAG, "external storage path = " + path);
- Log.d(TAG, "external storage value = " + value);
- }
- };
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
- filter.addAction(Intent.ACTION_MEDIA_BUTTON);
- filter.addAction(Intent.ACTION_MEDIA_CHECKING);
- filter.addAction(Intent.ACTION_MEDIA_EJECT);
- filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
- filter.addAction(Intent.ACTION_MEDIA_NOFS);
- filter.addAction(Intent.ACTION_MEDIA_REMOVED);
- filter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
- filter.addAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- filter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
- filter.addAction(Intent.ACTION_MEDIA_SHARED);
- filter.addAction(Intent.ACTION_MEDIA_UNMOUNTABLE);
- filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
- // 必须添加,否则无法接收到广播
- filter.addDataScheme("file");
- registerReceiver(externalStorageReceiver, filter);
- }
- }
- /**
- * 取消注册
- */
- private void unregisterReceivers() {
- if (externalStorageReceiver != null) {
- unregisterReceiver(externalStorageReceiver);
- externalStorageReceiver = null;
- }
- }
- }
- 上一篇Service: onStartCommand 诡异的返回值
- 下一篇FAQ_21 sqlite exception: close() was never explicitly called on database
- 顶
- 5
- 踩
- 0
- 主题推荐
- 存储broadcastreceiver 文件系统 操作系统 frameworks
- 猜你在找
- MediaScanner与音乐信息扫描==
- android 修改默认时间为24小时格式
- Android OOM ,回收布局文件中ImageView占用的内存.Bitmap OOM回收解决.
- 切换音效会导致有杂音
- jquery 漂浮广告
- JNI: Get/ReleaseStringUTFChars和Get/ReleaseIntArrayElements的区别,isCopy是否重新分配内存的问题
- Tabhost里面的Activity刷新问题--(Activity生命周期)
- Android中的RefBase,sp和wp
- libjpeg 详解
- Android程序 依赖库引用Gson 报java.lang.NoClassDefFoundError: com/google/gson/Gson 解决方法
暂无评论
核心技术类目
- 个人资料
- 访问:396307次
- 积分:7280分
- 排名:第695名
- 原创:215篇
- 转载:13篇
- 译文:2篇
- 评论:375条
verycool
- 文章分类
- OpenSource(6)
- Refactoring/Pattern(5)
- Android 技术笔记(49)
- Android packages/app(4)
- Android View/UI(26)
- Android 系统专题(15)
- Algorithm(7)
- linux/ubuntu(21)
- JavaSE(46)
- C/C++(5)
- database(13)
- WEB开发(7)
- 7上8下(18)
- FAQ(24)
- 评论排行
- Handler:更新UI的方法(28)
- Handler: 主线程如何通知子线程(24)
- UI效果(5): 实现Activity刷新(17)
- 情结- WiFi 直连(17)
- Handler: Activity 之间通过 Handler 通信(15)
- Java基础:IO 流中的 flush(14)
- View编程(3): invalidate()源码分析(13)
- 注意身体(12)
- View编程(1): Window、View与setContentView()(11)
- MySQL: 基于 android 远程连接(10)
- 阅读排行
- Handler:更新UI的方法(16289)
- UI效果(5): 实现Activity刷新(10687)
- Handler: 主线程如何通知子线程(9169)
- Spinner(3): OnItemSelectedListener 触发时机(9104)
- network: android 使用广播监听网络状态(8530)
- adb:) adb install(7529)
- Handler: Activity 之间通过 Handler 通信(7403)
- FAQ_07_android:clickable 问题(6840)
- adb:) adb push、pull、logcat and etc(6156)
- Java基础:IO 流中的 flush(6001)
- 推荐文章
- Service: 监听外部存储设备
- Service: 监听外部存储设备
- Service: 监听外部存储设备
- Service: 监听外部存储设备
- 监听外部存储设备
- Android监听外部存储设备的状态(SD卡、U盘等等)
- Android监听外部存储设备的状态(SD卡、U盘等等)
- Android监听外部存储设备的状态(SD卡、U盘等等)
- android 获取外部存储设备路径
- Android 获取外部存储设备列表
- android 监听检测USB存储设备
- Android存储和加载本地文件(外部存储设备)
- Android设备中的内部存储和外部存储
- Android从外部存储设备中读取,或存储数据
- 狂刷Android范例之3:读写外部存储设备
- Android 关于外部存储设备挂载路径获取问题
- 外部存储
- 外部存储
- Maven java通过jdbc连接Hive 执行HQL语句
- Linux的hadoop部署
- malloc()参数为0的情况
- Repeater 鼠标指向行,背景变色.
- 系统安装注意事项
- Service: 监听外部存储设备
- 在ScrollView 每页中添加固定按钮 参考ScrollView简单使用
- ABBYY FlexiCapture Engine使用心得分享
- 漫谈C语言及如何学习C语言 转自 http://sunxiunan.com/?p=1661
- 设计模式简单整理
- 用 Annotation 讲解
- Struts1框架的使用
- 隐马尔可夫模型
- Matlab中的线型、标记和颜色