Android 多媒体扫描过程.docx_第1页
Android 多媒体扫描过程.docx_第2页
Android 多媒体扫描过程.docx_第3页
Android 多媒体扫描过程.docx_第4页
Android 多媒体扫描过程.docx_第5页
已阅读5页,还剩16页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Android 多媒体扫描过程(Android Media Scanner Process) 下面是系统 图 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代码 public class MediaScannerReceiver extends BroadcastReceiver private final static StringTAG= MediaScannerReceiver ; Override public void onReceive(Contextcontext,Intentintent) Stringaction=intent.getAction(); Uriuri=intent.getData(); StringexternalStoragePath=Environment.getExternalStorageDirectory().getPath(); if (action.equals(Intent.ACTION_BOOT_COMPLETED) /scaninternalstorage scan(context,MediaProvider.INTERNAL_VOLUME); else if (uri.getScheme().equals( file ) /handleintentsrelatedtoexternalstorage Stringpath=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(Contextcontext,Stringvolume) Bundleargs=new Bundle(); args.putString(volume ,volume); context.startService( new Intent(context,MediaScannerService. class ).putExtras(args); private void scanFile(Contextcontext,Stringpath) Bundleargs=new Bundle(); args.putString(filepath ,path); context.startService( new Intent(context,MediaScannerService. class ).putExtras(args); Java代码 publicclassMediaScannerReceiverextendsBroadcastReceiver privatefinalstaticStringTAG=MediaScannerReceiver; OverridepublicvoidonReceive(Contextcontext,Intentintent) Stringaction=intent.getAction(); Uriuri=intent.getData(); StringexternalStoragePath=Environment.getExternalStorageDirectory().getPath(); if(action.equals(Intent.ACTION_BOOT_COMPLETED) /scaninternalstorage scan(context,MediaProvider.INTERNAL_VOLUME); else if(uri.getScheme().equals(file) /handleintentsrelatedtoexternalstorage Stringpath=uri.getPath(); if(action.equals(Intent.ACTION_MEDIA_MOUNTED)& externalStoragePath.equals(path) scan(context,MediaProvider.EXTERNAL_VOLUME); elseif(action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)& path!=null&path.startsWith(externalStoragePath+/) scanFile(context,path); privatevoidscan(Contextcontext,Stringvolume) Bundleargs=newBundle(); args.putString(volume,volume); context.startService( newIntent(context,MediaScannerService.class).putExtras(args); privatevoidscanFile(Contextcontext,Stringpath) Bundleargs=newBundle(); args.putString(filepath,path); context.startService( newIntent(context,MediaScannerService.class).putExtras(args); 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代码 public void allScan() sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse( file:/ +Environment.getExternalStorageDirectory(); Java代码 publicvoidallScan() sendBroadcast(newIntent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse(file:/+Environment.getExternalStorageDirectory(); public void allScan() sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse(file:/ + Environment.getExternalStorageDirectory(); - 通过 Intent.ACTION_MEDIA_SCANNER_SCAN_FILE 扫描某个文件 Java代码 public void fileScan(StringfName) Uridata=Uri.parse(file:/ +fName); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); Java代码 publicvoidfileScan(StringfName) Uridata=Uri.parse(file:/+fName); sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); 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代码 public void fileScan(Stringfile) Uridata=Uri.parse(file:/ +file); Log.d(TAG , file: +file); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); public void folderScan(Stringpath) Filefile=new File(path); if (file.isDirectory() Filearray=file.listFiles(); for ( int i= 0 ;iarray.length;i+) Filef=arrayi; if (f.isFile() /FILETYPE Stringname=f.getName(); if (name.contains( .mp3 ) fileScan(f.getAbsolutePath(); else /FOLDERTYPE folderScan(f.getAbsolutePath(); Java代码 publicvoidfileScan(Stringfile) Uridata=Uri.parse(file:/+file); Log.d(TAG,file:+file); sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); publicvoidfolderScan(Stringpath) Filefile=newFile(path); if(file.isDirectory() Filearray=file.listFiles(); for(inti=0;iarray.length;i+) Filef=arrayi; if(f.isFile()/FILETYPE Stringname=f.getName(); if(name.contains(.mp3) fileScan(f.getAbsolutePath(); else/FOLDERTYPE folderScan(f.getAbsolutePath(); 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代码 public void systemScan() sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse( file:/ +Environment.getExternalStorageDirectory(); Java代码 publicvoidsystemScan() sendBroadcast(newIntent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse(file:/+Environment.getExternalStorageDirectory(); public void systemScan() sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse(file:/ + Environment.getExternalStorageDirectory(); - 扫描某个文件 参数:填入该文件的路径Java代码 public void fileScan(Stringfile) Uridata=Uri.parse(file:/ +file); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data); Java代码

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论