MediaScannerr完成android中的多媒体文件的扫描工作。例如,mediascanner扫描系统内存和SD卡文件之后,会将扫描的结果加载在数据库中,在Music这个应用程序中看到的显示在activity 的list列表上歌曲专辑名,流派,歌曲时长等信息,都是扫描后的结果放在数据库中,最后读到的数据库中的信息。
这里可以明白的一点是:多媒体数据库中的信息是由MediaScanner添加的。
MediaScanner这项功能使用到的三种android的基本组件:
(1)MediaScannerService(从Service中派生),完成扫描任务,并将扫描结果放入到媒体数据库中。
(2)MediaProvider(ContentProvider派生),针对媒体库进行相关操作请求,一般情况就是写,删,查,更操作。
(3)MediaScannerReceiver接收外界的扫描请求,这里可以看出它MediaScanner的对外接口。
(这里也是提个醒,不是按照MediaRecorder和MediaPlayer的接口那样的使用方式)
MediaScanner扫描工作的流程总结:
首先,外界应该有扫描请求,所有MediaScannerReceiver首先会接收这些请求,得到请求之后需要完成工作扫描工作,这个是由MediaScannerService完成的,所以MediaScannerReceiver利用startService来启动MediaScannerService。在MediaScannerService的工作中,主线和工作线程是分开的,主线程接收请求,工作线程完成
扫描任务。
其次,工作线程正式开始工作,创建扫描器MediaScanner来处理请求中的扫描目标。扫描前会向系统发送广播,扫描工作完成后,做一点儿后期处理也会向系统发送扫描完毕广播。
总结的说,调用关系是 MediaScannerReceiver(对外的接口) ---> MediaScanner(扫描执行,这里要知道的是MediaScanner扫描器是在MediaScannerService中创建出来的)MediaScanner和MediaScannerService是宿主关系。
开始工作: 根据这个扫描过程看看这里的重点类跟函数:
1. 分析MediaScannerReceive.java:
public class MediaScannerReceiver extends BroadcastReceiver{ };
这里继承了一个广播类BroadcastReceiver,就是说MediaScannerReceiver是用来接收广播的。
MediaScannerReceiver接收的有效广播有三种,而且对这三种广播的处理都是在OnCreate()函数中完成。
广播一:BOOT_COMPLETED 此时处理的是系统内存上信息的扫描工作。路径:/system/media,这部分的内容主要是系统自带的铃声等文件,这个内存比较小。
广播二:MEDIA_MOUNTED 扫描SD卡,当然是包括内置和外置的SD卡,外部存储挂载路径必须为:/mnt/sdcard.
广播三:MEDIA_SCANNER_SCAN_FILE 处理的是sd卡上的文件,也就是说在路径:/system/media上面。
对广播的处理其实就是接下来启动startService让MediaScannerService工作完成扫描任务的过程。
代码:
public void onReceive(Context context, Intent intent) {
// 从intent中得到对应ACTION的广播动作对应的路径资源URI
// scan()函数工作。首先字符串匹配之后就使用scan(),在scan()中真正工作的是startService(),startService()作用是启动MediaScannerService,MediaScannerReceive的工作就告一段落了,接下来就看MediaScannerService如何使用工作线程完成扫描工作了。
2. MediaScannerService.java
class MediaScannerService extends Service implements Runnable,实现这个Runnable接口,这就是说至此会创建工作线程。
Service的函数执行顺序是:首先OnCreate(),然后OnStartCommand(),就是每次MediaScannerReceiver执行scan()即startService(),就会激发一次OnStartCommand()。
(1)OnCreate(){
// 实现一个工作线程的创建,这个线程是使用消息处理机制,有一个run()函数的工作。
Thread thr = new Thread(null, this, "MediaScannerService")
};
(2)OnStartCommand()函数
int onStartCommand(Intent intent, int flags, int startId)
{
// i. 从 Intent intent中获取请求处理的消息
// ii. 接收的消息交给Handler工作线程,然后被工作线程处理。
mServiceHandler.sendMessage(msg);
}
onStartCommand()完成的是消息传递。
(3)ServiceHandler的handleMessage()处理请求。
private final class ServiceHandler extends Handler{
// scan完成工作
void scan(String[] directories, String volumeName);
stopSelf(msg.arg1);
}
MediaScannerService中的scan()函数中创建MediaScanner扫描器,MediaScanner scanner = createMediaScanner();再一层剖析createMediaScanner()函数:
private MediaScanner createMediaScanner() {
MediaScanner scanner = new MediaScanner(this); //创建MediaScanner对象
Locale locale = getResources().getConfiguration().locale; // 得到系统的相关信息,支持的国家和支持的语言
scanner.setLocale(language + "_" + country);//为扫描器设置当前系统使用的国家和语言
}
至此,工作流程的分析完成,下一层主要是分析重点MediaScanner如何工作。