设为首页 收藏本站
查看: 1621|回复: 0

[Cloudstack] Service: 监听外部存储设备

[复制链接]

尚未签到

发表于 2015-10-14 09:43:23 | 显示全部楼层 |阅读模式

  • 登录 | 注册


CodingMan
--- what is most important?

  • DSC0000.gif 目录视图
  • DSC0001.gif 摘要视图
  • DSC0002.gif 订阅
有奖征资源,博文分享有内涵        4月推荐博文汇总        CSDN博客支持Windows Live Writer离线写博客啦Service: 监听外部存储设备
分类: Android 技术笔记 2012-05-25 23:50 2495人阅读 评论(0)收藏 举报service存储actionstringpath测试  博客声明:
  

  1. 使用 android2.1 源码说明问题
  

  2. 使用真机,操作系统是 android-2.1
  

  3. 分享一下学习方法,不是为了测试而测试,请大家举一反三
  

  结合 Service 与 Broadcast 监听外部存储设备的状态,通过测试主要想知道在我们操作外部存储设备时候发生了哪些事情、以及 Intent 几个 Action 到底是何意?
  

  测试代码见 附录,至于如何启动这个 Service,随您意!
  

  主要的 Action
  

                                    DSC0003.png

  

  

  注册这 13 个 action,然后运行 app ,点击 back 服务退至后台。
  

  now,ready!来操作 sdcard。
  

  1.  直接拔掉 sdcard
  

   DSC0004.png
  

  2.  再次将 sdcard 插入卡槽
  
  

   DSC0005.png

  

  先大概 1-3 秒的 media checking,然后才是 mounted -- scanner started -- scanner finished
  

  3.  在通知栏卸载 sdcard
  

   DSC0006.png

  

  

  紧接着,从卡槽拔出 sdcard(必须拔出,才会接收到下面的 action)
  

   DSC0007.png

  

  可以看出,这种情况属于正常卸载 sdcard,不是强制拔出。不同于 1.
  

  这个时候,你将 sdcard 插入卡槽,发生的情况与 2 一致。
  

  

  4. 在通知栏选择 "计算机与 sd 卡之间复制文件",即共享
  

  在弹出的对话框选择 "装载"
  

   DSC0008.png

  

  然后,我们再次在通知栏选择 "关闭 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?

  •        @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 看看:
  

  
[java] view plaincopyprint?

  • @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 方法里面得到这个值
  

  finalString path = intent.getData().getPath()

  

  其实,就是 "/sdcard" (即 sd卡路径)。
  

  这个信息很有用!!!
  

  比如你的手机可以外括除了 sd 卡的其它外部设备(如u 盘、map 卡)
  那麽这个返回的路径就不一样,可以根据返回的路径判断你当前操作的是哪个设备了!
  

  耶耶,酷比嘞!
  

  在 MountService.java里面还有一个与众不同的地方:
  

  
[java] view plaincopyprint?

  • 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
  

  
[java] view plaincopyprint?

  • 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;  
  •         }  
  •     }  
  •   
  • }  


  

  

  

  

  

  
  

更多0

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-126509-1-1.html 上篇帖子: HQL语言入门 下篇帖子: Eucalyptus
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表