概述:
MediaScanner和媒体文件扫描有关,例如music的歌曲专辑名、播放时长,图片的大小、MINE类型等,都是它扫描得到的。我们应用程序通过MediaStore接口查询媒体数据库得到的多媒体数据也和MediaScanner有关,因为数据库里面的数据都是MediaScanner添加的。总体关系如下图:
MediaScanner大体分为四个部分
MediaScannerReceiver:
负责接收外界发来的扫描请求广播,如Intent.ACTION_BOOT_COMPLETED开机广播、Intent.ACTION_MEDIA_MOUNTED由MountService发送的挂载广播、Intent.ACTION_MEDIA_SCANNER_SCAN_FILE应用程序可以发送扫描广播。同时,在接收到广播之后,它会调用MediaScannerService去执行下一步动作,如下:
private void scan(Context context, String volume) {
Bundle args = new Bundle();
args.putString("volume", volume);
context.startService(
new Intent(context, MediaScannerService.class).putExtras(args));
}
MediaScannerService:
负责扫描文件的后台服务,在创建服务的时候,会开启一个优先级比较低的子线程,扫描的任务就在这个子线程里完成。在扫描前和扫描后分别会发送广播Intent.ACTION_MEDIA_SCANNER_STARTED和Intent.ACTION_MEDIA_SCANNER_FINISHED。在做好一些前期的准备,如打开数据库之类的动作之后,会创建MediaScanner类的实例,把真正扫描的工作交给MediaScanner,如下:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri));
try {
if (volumeName.equals(MediaProvider.EXTERNAL_VOLUME)) {
openDatabase(volumeName);
}
try (MediaScanner scanner = new MediaScanner(this, volumeName)) {
scanner.scanDirectories(directories);
}
} catch (Exception e) {
Log.e(TAG, "exception in MediaScanner.scan()", e);
}
getContentResolver().delete(scanUri, null, null);
MediaScanner:
处理具体扫描文件并添加数据库的操作类,分为Java层和jni层。首先构造函数中会获取各个表的URI
mAudioUri = Audio.Media.getContentUri(volumeName);
mVideoUri = Video.Media.getContentUri(volumeName);
mImagesUri = Images.Media.getContentUri(volumeName);
mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
mFilesUri = Files.getContentUri(volumeName);
在执行扫描前会执行prescan(String filePath, boolean prescanFiles)这样一个动作,去删除掉数据库中存在,但是实际文件已经不存在的数据项。然后执行postscan(final String[] directories)执行扫描入库的操作。
MediaProvider:
集成ContentProvider,用来存储和增删改查数据。同时,引入MediaStore这类,它包含了内部类Audio、Files、Images、Video,每一个内部类都定义了该类型所需要的字段常量,可以使开发者很方便地使用和管理。