




已阅读5页,还剩41页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android多媒体扫描过程(AndroidMediaScannerProcess)下面是系统图 MediaScannerReceiver 会在任何的 ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED 或 ACTION_MEDIA_SCANNER_SCAN_FILE 意图( intent )发出的时候启动。因为解析媒体文件 的元数据 或许会需要很长时间 ,所以 MediaScannerReceiver 会启动 MediaScannerService 。 MediaScannerService 调用一个公用类 MediaScanner 去处理真正的工作。 MediaScannerReceiver 维持两种扫描目录:一种是内部卷( internal volume )指向 $(ANDROID_ROOT)/media. 另一种是外部卷( external volume )指向 $(EXTERNAL_STORAGE). 扫描和解析工作位于 JAVA 层和 C+ 层。 JAVA 层是启动器。 MediaScanner 扫描所有目录,如下步骤: 1.JAVA 层初始化 在这一步骤中,它会根据目录是在内部卷还是外部卷打开不同的数据库 。 2.Java 层预扫描 首先清除文件和播放 列表的缓存条目。然后根据 MediaProvider 返回的请求结果生成新文件和播放列表缓存条目。 3.C+ 层处理目录 列举出所有文件和特定的所有子目录(如果子目录包含一个 .nomedia 隐藏文件,则不会被列举出来。)。被列举的文件是根据文件扩展来判断文件是否被支持。如果支持这种文件扩展, C+ 层就会回调到 JAVA 层扫描文件。这种扩展就会被扫描到 MediaFile.java 中列出。下面是支持的文件扩展列表。 /* Audio */ addFileType(MP3, FILE_TYPE_MP3, audio/mpeg); addFileType(M4A, FILE_TYPE_M4A, audio/mp4); addFileType(WAV, FILE_TYPE_WAV, audio/x-wav); addFileType(AMR, FILE_TYPE_AMR, audio/amr); addFileType(AWB, FILE_TYPE_AWB, audio/amr-wb); addFileType(WMA, FILE_TYPE_WMA, audio/x-ms-wma); addFileType(OGG, FILE_TYPE_OGG, application/ogg); addFileType(MID, FILE_TYPE_MID, audio/midi); addFileType(XMF, FILE_TYPE_MID, audio/midi); addFileType(RTTTL, FILE_TYPE_MID, audio/midi); addFileType(SMF, FILE_TYPE_SMF, audio/sp-midi); addFileType(IMY, FILE_TYPE_IMY, audio/imelody); /* Video */ addFileType(MP4, FILE_TYPE_MP4, video/mp4); addFileType(M4V, FILE_TYPE_M4V, video/mp4); addFileType(3GP, FILE_TYPE_3GPP, video/3gpp); addFileType(3GPP, FILE_TYPE_3GPP, video/3gpp); addFileType(3G2, FILE_TYPE_3GPP2, video/3gpp2); addFileType(3GPP2, FILE_TYPE_3GPP2, video/3gpp2); addFileType(WMV, FILE_TYPE_WMV, video/x-ms-wmv); /* Image */ addFileType(JPG, FILE_TYPE_JPEG, image/jpeg); addFileType(JPEG, FILE_TYPE_JPEG, image/jpeg); addFileType(GIF, FILE_TYPE_GIF, image/gif); addFileType(PNG, FILE_TYPE_PNG, image/png); addFileType(BMP, FILE_TYPE_BMP, image/x-ms-bmp); addFileType(WBMP, FILE_TYPE_WBMP, image/vnd.wap.wbmp); /* Audio Play List */ addFileType(M3U, FILE_TYPE_M3U, audio/x-mpegurl); addFileType(PLS, FILE_TYPE_PLS, audio/x-scpls); addFileType(WPL, FILE_TYPE_WPL, application/vnd.ms-wpl); 4.Java 层扫描文件 a ) Java 层开始文件 首先它忽略一些 MacOS 和 Windows Media Player 特殊的文件。然后它会查看被扫描的文件是否已经存在于缓存条目中,如果存在,它会检查文件上次修改的时间是否改变。最后它返回该文件是否需要进一步处理的结果。如果不需要,接下来的两步不会执行。 b)C+ 层扫描文件 不是所有的文件都需要交给 C+ 层解析成元数据。只有下面的文件类型会被解析,注意,这里不处理 image 文件。 if (mFileType = MediaFile.FILE_TYPE_MP3 | mFileType = MediaFile.FILE_TYPE_MP4 | mFileType = MediaFile.FILE_TYPE_M4A | mFileType = MediaFile.FILE_TYPE_3GPP | mFileType = MediaFile.FILE_TYPE_3GPP2 | mFileType = MediaFile.FILE_TYPE_OGG | mFileType = MediaFile.FILE_TYPE_MID | mFileType = MediaFile.FILE_TYPE_WMA) 复制代码 对于被解析的元数据信息, C+ 层会回调到 JAVA 层的 handleStringTag 。 Java 层会记录它的 name/value 信息。 c)Java 层结束文件 最后根据上一步解析出的值, Java 层会更新相应的 MeidaProvider 产生的数据库表。 5.Java 层发送扫描 到目前为止,所有文件已经被扫描,它最后会检查文件和播放列表缓存条目,看是否所有项仍然存在于文件系统。如果有空条目,则会从数据库中删除。这样它能够保持数据库和文件系统的一致性。 其他的应用 程序 通过接收 MediaScannerService 发出的 ACTION_MEDIA_SCANNER_STARTED 和 ACTION_MEDIA_SCANNER_FINISHED 意图能够知道什么时候扫描操作开始和结束。 MediaScanner之所以拿MediaScanner开刀 因为想借用系统的Media Scan 工具 通过Intent直接调用系统的步骤1. 下载并安装Git 过程略 网络上很多2. 得到该功能的模块地址并使用Git下载之 地址:git://platform/packages/providers/MediaProvider.git 3. 分析源代码: - AndroidManifest.xml : 各组件属性描述文件 - MediaProvider : extends ContentProvider 使用SQLiteDatabase 保存查询数据 action=content:/media - MediaScannerCursor.java - MediaScannerReceiver : extends BroadcastReceiver 用于接收指定Broadcast: BOOT_COMPLETED MEDIA_MOUNTED MEDIA_SCANNER_SCAN_FILE 并启动 MediaScannerService 开始扫描 - MediaScannerService : extends Service 执行具体的扫描工作 - MediaThumbRequest 4. 鉴于 并不打算自行实现多媒体扫描 因此 此次重点研究对象:MediaScannerReceiver 5.MediaScannerReceiver 代码 Java代码 1. public class MediaScannerReceiver extends BroadcastReceiver 2. 3. private final static StringTAG= MediaScannerReceiver ; 4. 5. Override 6. public void onReceive(Contextcontext,Intentintent) 7. Stringaction=intent.getAction(); 8. Uriuri=intent.getData(); 9. StringexternalStoragePath=Environment.getExternalStorageDirectory().getPath(); 10. 11. if (action.equals(Intent.ACTION_BOOT_COMPLETED) 12. /scaninternalstorage 13. scan(context,MediaProvider.INTERNAL_VOLUME); 14. else 15. if (uri.getScheme().equals( file ) 16. /handleintentsrelatedtoexternalstorage 17. Stringpath=uri.getPath(); 18. if (action.equals(Intent.ACTION_MEDIA_MOUNTED)& 19. externalStoragePath.equals(path) 20. scan(context,MediaProvider.EXTERNAL_VOLUME); 21. else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)& 22. path!=null &path.startsWith(externalStoragePath+ / ) 23. scanFile(context,path); 24. 25. 26. 27. 28. 29. private void scan(Contextcontext,Stringvolume) 30. Bundleargs=new Bundle(); 31. args.putString(volume ,volume); 32. context.startService( 33. new Intent(context,MediaScannerService. class ).putExtras(args); 34. 35. 36. private void scanFile(Contextcontext,Stringpath) 37. Bundleargs=new Bundle(); 38. args.putString(filepath ,path); 39. context.startService( 40. new Intent(context,MediaScannerService. class ).putExtras(args); 41. 42. public class MediaScannerReceiver extends BroadcastReceiver private final static String TAG = MediaScannerReceiver; Override public void onReceive(Context context, Intent intent) String action = intent.getAction(); Uri uri = intent.getData(); String externalStoragePath = Environment.getExternalStorageDirectory().getPath(); if (action.equals(Intent.ACTION_BOOT_COMPLETED) / scan internal storage scan(context, MediaProvider.INTERNAL_VOLUME); else if (uri.getScheme().equals(file) / handle intents related to external storage String path = uri.getPath(); if (action.equals(Intent.ACTION_MEDIA_MOUNTED) & externalStoragePath.equals(path) scan(context, MediaProvider.EXTERNAL_VOLUME); else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) & path != null & path.startsWith(externalStoragePath + /) scanFile(context, path); private void scan(Context context, String volume) Bundle args = new Bundle(); args.putString(volume, volume); context.startService( new Intent(context, MediaScannerService.class).putExtras(args); private void scanFile(Context context, String path) Bundle args = new Bundle(); args.putString(filepath, path); context.startService( new Intent(context, MediaScannerService.class).putExtras(args); 6. 根据以上代码得知:- 当系统启动完毕 会扫描一次- 当 ACTION_MEDIA_MOUNTED ACTION_MEDIA_SCANNER_SCAN_FILE 也会扫描7. 如何调用系统MediaScanner 进行扫描- 通过 Intent.ACTION_MEDIA_MOUNTED 进行全扫描Java代码 1. public void allScan() 2. sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse( file:/ 3. +Environment.getExternalStorageDirectory(); 4. public void allScan() sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse(file:/ + Environment.getExternalStorageDirectory(); - 通过 Intent.ACTION_MEDIA_SCANNER_SCAN_FILE 扫描某个文件 Java代码 1. public void fileScan(StringfName) 2. Uridata=Uri.parse(file:/ +fName); 3. sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); 4. public void fileScan(String fName) Uri data = Uri.parse(file:/+fName); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data); 补充: 上述方法是不支持对文件夹的 即:Uri data 必须是 文件的Uri 如果是文件夹的 其不会起作用的 切记! - 如何扫描某文件夹下所有文件 难道就不可以么? 当然不 借助于Intent.ACTION_MEDIA_SCANNER_SCAN_FILE 我们可以这么做: 取出该文件夹下的所有子文件 如其是文件且类型符合条件 就取出该文件目录 以Intent.ACTION_MEDIA_SCANNER_SCAN_FILE方式发送至MediaScannerReceiver 若其为文件夹 则迭代查询之 故实现为:Java代码 1. public void fileScan(Stringfile) 2. Uridata=Uri.parse(file:/ +file); 3. 4. Log.d(TAG , file: +file); 5. sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); 6. 7. 8. public void folderScan(Stringpath) 9. Filefile=new File(path); 10. 11. if (file.isDirectory() 12. Filearray=file.listFiles(); 13. 14. for ( int i= 0 ;iarray.length;i+) 15. Filef=arrayi; 16. 17. if (f.isFile() /FILETYPE 18. Stringname=f.getName(); 19. 20. if (name.contains( .mp3 ) 21. fileScan(f.getAbsolutePath(); 22. 23. 24. else /FOLDERTYPE 25. folderScan(f.getAbsolutePath(); 26. 27. 28. 29. public void fileScan(String file) Uri data = Uri.parse(file:/+file); Log.d(TAG,file:+file); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data); public void folderScan(String path) File file = new File(path); if(file.isDirectory() File array = file.listFiles(); for(int i=0;iarray.length;i+) File f = arrayi; if(f.isFile()/FILE TYPE String name = f.getName(); if(name.contains(.mp3) fileScan(f.getAbsolutePath(); else /FOLDER TYPE folderScan(f.getAbsolutePath(); 8. 鉴于多数人并不关心其原理 仅关系如何使用 故 总结如下:- 扫描全部 我猜测其在效率方面可能有点副作用 Java代码 1. public void systemScan() 2. sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse( file:/ 3. +Environment.getExternalStorageDirectory(); 4. - 扫描某个文件 参数:填入该文件的路径Java代码 1. public void fileScan(Stringfile) 2. Uridata=Uri.parse(file:/ +file); 3. 4. sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); 5. - 扫描文件夹 参数:填入该文件夹路径Java代码 1. public void fileScan(Stringfile) 2. Uridata=Uri.parse(file:/ +file); 3. 4. sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); 5. 6. 7. public void folderScan(Stringpath) 8. Filefile=new File(path); 9. 10. if (file.isDirectory() 11. Filearray=file.listFiles(); 12. 13. for ( int i= 0 ;iarray.length;i+) 14. Filef=arrayi; 15. 16. if (f.isFile() /FILETYPE 17. Stringname=f.getName(); 18. 19. if (name.contains( .mp3 ) 20. fileScan(f.getAbsolutePath(); 21. 22. 23. else /FOLDERTYPE 24. folderScan(f.getAbsolutePath(); 25. 26. 27. 28. public void fileScan(String file) Uri data = Uri.parse(file:/+file); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data); public void folderScan(String path) File file = new File(path); if(file.isDirectory() File array = file.listFiles(); for(int i=0;iarray.length;i+) File f = arrayi; if(f.isFile()/FILE TYPE String name = f.getName(); if(name.contains(.mp3) fileScan(f.getAbsolutePath(); else /FOLDER TYPE folderScan(f.getAbsolutePath(); 终于结束了 看似简单的东西 研究起来 还是挺复杂的!Android Media Scanner Mechanism Analyze ArchitectureFigure 2-1As Figure 2-1. MediaScannerReciver start up at anytime where receive intent ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED or ACTION_MEDIA_SCANNER_SCAN_FILE. Cause on that spend long time to process the media metadata, so that MediaScannerReceiver will call up MediaScannerService.MediaScannerService invoke a public class which named MediaScanner to do the scan work, MediaScanner handle the media database with a public class which named MediaProviderMediaScannerReciver support two types of the folder: 1.internal volume, point to $(ANDROID_ROOT)/media. 2.External volume, point $(EXTERNAL_STORAGE).Scanner ActionACTION_BOOT_COMPLETEDpublic static finalStringACTION_BOOT_COMPLETEDBroadcast Action: This is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization, such as installing alarms. You must hold theRECEIVE_BOOT_COMPLETEDpermission in order to receive this broadcast.This is a protected intent that can only be sent by the system.Constant Value:ent.action.BOOT_COMPLETEDACTION_MEDIA_MOUNTEDpublic static finalStringACTION_MEDIA_MOUNTEDBroadcast Action: External media is present and mounted at its mount point. The path to the mount point for the removed media is contained in the Intent.mData field. The Intent contains an extra with name read-only and Boolean value to indicate if the media was mounted read only.Constant Value:ent.action.MEDIA_MOUNTEDACTION_MEDIA_SCANNER_SCAN_FILE.public static finalStringACTION_MEDIA_SCANNER_SCAN_FILEBroadcast Action: Request the media scanner to scan a file and add it to the media database. The path to the file is contained in the Intent.mData field.Constant Value:ent.action.MEDIA_SCANNER_SCAN_FILEAndroid Media Scanner ReceiverWe can find the source file with path anydroid/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.javapublic class MediaScannerReceiver extends BroadcastReceiver Override public void onReceive(Context context, Intent intent) .if (action.equals(Intent.ACTION_BOOT_COMPLETED) / scan internal storage scan(context, MediaProvider.INTERNAL_VOLUME); else if (uri.getScheme().equals(file) / handle intents related to external storage String path = uri.getPath(); if (action.equals(Intent.ACTION_MEDIA_MOUNTED) & externalStoragePath.equals(path) scan(context, MediaProvider.EXTERNAL_VOLUME); else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) & path != null & path.startsWith(externalStoragePath + /) scanFile(context, path); private void scan(Context context, String volume) Bundle args = new Bundle(); args.putString(volume, volume); context.startService( new Intent(context, MediaScannerService.class).putExtras(args); private void scanFile(Context context, String path) Bundle args = new Bundle(); args.putString(filepath, path); context.startService( new Intent(context, MediaScannerService.class).putExtras(args); Figure 4-1As the source codes, and Figure 4-1, there are two different media database in the system, one is the internal storage , the other is the external storage. Finally, they call the method startService() to start the MediaScannerService.Android Media Scanner ServiceWe can find the source file with path /android/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerService.java .public void onCreate() .Thread thr = new Thread(null, this, MediaScannerService); thr.start(); public int onStartCommand(Intent intent, int flags, int startId) .Message msg = mServiceHandler.obtainMessage(); .mServiceHandler.sendMessage(msg); return Service.START_REDELIVER_INTENT; public void run() .mServiceHandler = new ServiceHandler(); .private final class ServiceHandler extends Handler .Override public void handleMessage(Message msg) .if (filePath != null) .Uri uri = scanFile(filePath, arguments.getString(mimetype); . else .scan(directories, volume); . private void scan(String directories, String volumeName) .MediaScanner scanner = createMediaScanner(); scanner.scanDirectories(directories, volumeName); .private Uri scanFile(String path, String mimeType) . MediaScanner scanner = createMediaScanner(); return scanner.scanSingleFile(path, volumeName, mimeType); Figure 5-1Android application maybe block with invoking se
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 宁波无尘室施工方案范本(3篇)
- 厕所土建施工方案(3篇)
- 致敬缅怀英烈活动方案策划(3篇)
- 景区节庆活动策划方案模板(3篇)
- 活动内容策划方案范文大全(3篇)
- 双绞网线施工方案(3篇)
- 安徽省马鞍山市雨山区2024-2025学年高二上学期期中考试历史试题含参考答案
- 项目管理 课件 第六章-项目成本管理
- 行政事务处理与活动策划工具
- 时空旅行高中政治课件
- 2025年秋新教科版三年级上册科学全册教案教学设计(新教材)
- 2025年云南省中考语文真题(附答案解析)
- 河南省洛阳市宜阳县2024-2025学年七年级下学期期末考试数学试卷(含答案)
- 第3讲 文言文内容概述题-据文比对判正误2026年高三语文第一轮总复习
- 房产抵押合同范本标准模板
- 二零二五年度汽车销售商与汽车电子设备供应商合作协议范本
- 2025版小学语文新课程标准
- 2025年中盐安徽红四方肥业股份有限公司招聘笔试参考题库附带答案详解
- GB/T 17642-2025土工合成材料非织造布复合土工膜
- ISO 37001-2025 反贿赂管理体系要求及使用指南(中文版-雷泽佳译-2025)
- 《望庐山瀑布》ppt完整版(共19页)课件
评论
0/150
提交评论