Service: 监听外部存储设备

来源:互联网 发布:空铁列车 知乎 编辑:程序博客网 时间:2024/05/08 09:39
有奖征资源,博文分享有内涵        4月推荐博文汇总        CSDN博客支持Windows Live Writer离线写博客啦

Service: 监听外部存储设备

分类: Android 技术笔记 2495人阅读 评论(0)收藏 举报
service存储actionstringpath测试

博客声明:


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 写自己的逻辑代码了。如:


[java] view plaincopyprint?
  1.        @Override  
  2. public void onReceive(Context context, Intent intent) {  
  3.     final String action = intent.getAction();  
  4.     if (Intent.ACTION_MEDIA_EJECT.equals(action)) {  
  5.         // 本人感觉 ACTION_MEDIA_EJECT 比  
  6.         //  ACTION_MEDIA_UNMOUNTED 好  
  7.           
  8.         // sd 卡不可用  
  9.     } else if (Intent.ACTION_MEDIA_REMOVED.equals(action)) {  
  10.         // sd 卡已经被移除卡槽  
  11.     } else if (Intent.ACTION_MEDIA_SHARED.equals(action)) {  
  12.         // 选择通过 usb 共享  
  13.     } else if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {  
  14.         // sd 卡可用  
  15.     }  
  16. }  

但是这里提醒一下:


接收到 ACTION_MEDIA_EJECT 广播之后,sd 卡还是可以读写的,

直到接收到 ACTION_MEDIA_REMOVED、ACTION_MEDIA_UNMOUNTED等广播之后,sd 卡才不可以读写。

可以借助 Music 源码 MediaPlaybackService.java 看看:


[java] view plaincopyprint?
  1. @Override  
  2. public void onReceive(Context context, Intent intent) {  
  3.     String action = intent.getAction();  
  4.     if (action.equals(Intent.ACTION_MEDIA_EJECT)) {  
  5.         saveQueue(true);  
  6.         mQueueIsSaveable = false;  
  7.         closeExternalStorageFiles(intent.getData().getPath());  
  8.     } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {  
  9.         mMediaMountedCount++;  
  10.         mCardId = MusicUtils.getCardId(MediaPlaybackService.this);  
  11.         reloadQueue();  
  12.         mQueueIsSaveable = true;  
  13.         notifyChange(QUEUE_CHANGED);  
  14.         notifyChange(META_CHANGED);  
  15.     }  
  16. }  


到这个时候,我们应该搞明白是系统哪个类发出这样的广播?有没有新的发现?


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 里面还有一个与众不同的地方:


[java] view plaincopyprint?
  1. void notifyMediaMounted(String path, boolean readOnly) {  
  2.         setMediaStorageNotification(000falsefalsenull);  
  3.         updateUsbMassStorageNotification(falsefalse);  
  4.         Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,   
  5.                 Uri.parse("file://" + path));  
  6.         intent.putExtra("read-only", readOnly);  
  7.         mMounted = true;  
  8.         mContext.sendBroadcast(intent);  
  9. }  


 intent.putExtra("read-only", readOnly)


其中 readOnly 是一个 boolean 值,在 onReceive 里面 只有 action 是 ACTION_MEDIA_MOUNTED,接收到该值是 false.





------------- 附录 


PlayerService.java


[java] view plaincopyprint?
  1. package mark.zhang;  
  2.   
  3. import android.app.Service;  
  4. import android.content.BroadcastReceiver;  
  5. import android.content.Context;  
  6. import android.content.Intent;  
  7. import android.content.IntentFilter;  
  8. import android.os.IBinder;  
  9. import android.util.Log;  
  10.   
  11. public class PlayerService extends Service {  
  12.     private static final String TAG = "PlayerService";  
  13.   
  14.     @Override  
  15.     public IBinder onBind(Intent intent) {  
  16.         return null;  
  17.     }  
  18.   
  19.     @Override  
  20.     public void onCreate() {  
  21.         super.onCreate();  
  22.         registerReceivers();  
  23.     }  
  24.   
  25.     @Override  
  26.     public int onStartCommand(Intent intent, int flags, int startId) {  
  27.         return super.onStartCommand(intent, flags, startId);  
  28.     }  
  29.   
  30.     @Override  
  31.     public void onDestroy() {  
  32.         Log.d(TAG, "onDestroy------");  
  33.         super.onDestroy();  
  34.         unregisterReceivers();  
  35.     }  
  36.   
  37.     private BroadcastReceiver externalStorageReceiver = null;  
  38.   
  39.     /** 
  40.      * 注册广播 
  41.      */  
  42.     private void registerReceivers() {  
  43.         if (externalStorageReceiver == null) {  
  44.             externalStorageReceiver = new BroadcastReceiver() {  
  45.   
  46.                 @Override  
  47.                 public void onReceive(Context context, Intent intent) {  
  48.                     final String action = intent.getAction();  
  49.                     final String path = intent.getData().getPath();  
  50.                     Log.d(TAG, "receive action = " + action);  
  51.                     boolean value = intent.getBooleanExtra("read-only"true);  
  52.                     Log.d(TAG, "external storage path = " + path);  
  53.                     Log.d(TAG, "external storage value = " + value);  
  54.                 }  
  55.             };  
  56.   
  57.             final IntentFilter filter = new IntentFilter();  
  58.             filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);  
  59.             filter.addAction(Intent.ACTION_MEDIA_BUTTON);  
  60.             filter.addAction(Intent.ACTION_MEDIA_CHECKING);  
  61.             filter.addAction(Intent.ACTION_MEDIA_EJECT);  
  62.             filter.addAction(Intent.ACTION_MEDIA_MOUNTED);  
  63.             filter.addAction(Intent.ACTION_MEDIA_NOFS);  
  64.             filter.addAction(Intent.ACTION_MEDIA_REMOVED);  
  65.             filter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);  
  66.             filter.addAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);  
  67.             filter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);  
  68.             filter.addAction(Intent.ACTION_MEDIA_SHARED);  
  69.             filter.addAction(Intent.ACTION_MEDIA_UNMOUNTABLE);  
  70.             filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);  
  71.             // 必须添加,否则无法接收到广播  
  72.             filter.addDataScheme("file");  
  73.   
  74.             registerReceiver(externalStorageReceiver, filter);  
  75.         }  
  76.     }  
  77.   
  78.     /** 
  79.      * 取消注册 
  80.      */  
  81.     private void unregisterReceivers() {  
  82.         if (externalStorageReceiver != null) {  
  83.             unregisterReceiver(externalStorageReceiver);  
  84.             externalStorageReceiver = null;  
  85.         }  
  86.     }  
  87.   
  88. }  









更多0
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 解决方法
查看评论

  暂无评论

* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
TOP
核心技术类目
全部主题JavaVPNAndroidiOSERPIE10EclipseCRMJavaScriptUbuntuNFCWAPjQuery数据库BIHTML5SpringApacheHadoop.NETAPIHTMLSDKIISFedoraXMLLBSUnitySplashtopUMLcomponentsWindows MobileRailsQEMUKDECassandraCloudStackFTCcoremailOPhoneCouchBase云计算iOS6RackspaceWeb AppSpringSideMaemoCompuware大数据aptechPerlTornadoRubyHibernateThinkPHPSparkHBasePureSolrAngularCloud FoundryRedisScalaDjangoBootstrap
    个人资料

    verycool
    • 访问:396307次
    • 积分:7280分
    • 排名:第695名
    • 原创:215篇
    • 转载:13篇
    • 译文:2篇
    • 评论:375条
    文章分类
  • 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)
    推荐文章

公司简介|招贤纳士|广告服务|银行汇款帐号|联系方式|版权声明|法律顾问|问题报告|合作伙伴|论坛反馈
网站客服杂志客服 微博客服 webmaster@csdn.net 400-600-2320
京 ICP 证 070598 号
北京创新乐知信息技术有限公司 版权所有
江苏乐知网络技术有限公司 提供商务支持
Copyright © 1999-2014, CSDN.NET, All Rights Reserved GongshangLogo

0 0
原创粉丝点击