[转载]Android开发——MediaProvider源码分析(2)

[转载]Android开发——MediaProvider源码分析(2) – 努力吧,专注Android – 博客园.

欲读此文,先读上文:MediaProvider源码分析(1)

———————-START—————————

在 上一篇文章中说到系统当接收到扫描请求广播的时候就会调用scan或者scanFile去扫描手机(手机内存和sdcard)中的媒体文件。这两个方法都 是启动MediaScannerService这个服务来完成扫描任务的。接下来我们来看看MediaScannerService是怎么工作的……

4.MediaScannerService(MSS)

MSS实现了Runnable,所以必然的需要实现run方法了,代码如下:

public void run()

{

// reduce priority below other background threads to avoid interfering

// with other services at boot time.

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND +

Process.THREAD_PRIORITY_LESS_FAVORABLE);

Looper.prepare();

mServiceLooper = Looper.myLooper();

mServiceHandler = new ServiceHandler();

Looper.loop();

}

在run方法中设置了线程的优先级,优先级比较低,主要为了避免跟其他服务抢夺资源。还有就是利用looper对ServiceHandler的消息进行循环控制。

接着看一下ServiceHandler的实现代码:

private final class ServiceHandler extends Handler

{

@Override

public void handleMessage(Message msg)

{

Bundle arguments = (Bundle) msg.obj;

//获取文件路径

String filePath = arguments.getString("filepath");

try {

if (filePath != null) {

//文件路径不为空,则调用扫面当个文件的方法

IBinder binder = arguments.getIBinder("listener");

IMediaScannerListener listener =

(binder == null ? null : IMediaScannerListener.Stub.asInterface(binder));

Uri uri = scanFile(filePath, arguments.getString("mimetype"));//扫描单个文件

if (listener != null) {

//执行扫描完成方法

listener.scanCompleted(filePath, uri);

}

} else {

//如果文件路径为空,则获取扫面手机内存或者sdcard

String volume = arguments.getString("volume");

String[] directories = null;

//内置卡

if (MediaProvider.INTERNAL_VOLUME.equals(volume)) {

// scan internal media storage

directories = new String[] {

Environment.getRootDirectory() + "/media",

};

}//外置卡

else if (MediaProvider.EXTERNAL_VOLUME.equals(volume)) {

// scan external storage

directories = new String[] {

Environment.getExternalStorageDirectory().getPath(),

};

}

if (directories != null) {

if (Config.LOGD) Log.d(TAG, "start scanning volume " + volume);

//扫描

scan(directories, volume);

if (Config.LOGD) Log.d(TAG, "done scanning volume " + volume);

}

}

} catch (Exception e) {

Log.e(TAG, "Exception in handleMessage", e);

}

stopSelf(msg.arg1);

}

};

以上三个方法是属于Service的生命周期的。当我们调用startService的时候,如果对应的Service还未创建就会调用 onCreate方法===方法。每次startService的时候就调用onStartCommand,所以ServiceHandler就在此发送 消息了。

最后,稍微看一下MSS里面扫描方面。主要是调用MediaScanner对媒体文件进行扫描分析的。至于MediaScanner的实现以后在分析。

private void openDatabase(String volumeName) {

try {

ContentValues values = new ContentValues();

values.put("name", volumeName);

getContentResolver().insert(Uri.parse("content://media/"), values);

} catch (IllegalArgumentException ex) {

Log.w(TAG, "failed to open media database");

}

}

private void closeDatabase(String volumeName) {

try {

getContentResolver().delete(

Uri.parse("content://media/" + volumeName), null, null);

} catch (Exception e) {

Log.w(TAG, "failed to close media database " + volumeName + " exception: " + e);

}

}

//创建扫描器

private MediaScanner createMediaScanner() {

MediaScanner scanner = new MediaScanner(this);

Locale locale = getResources().getConfiguration().locale;

if (locale != null) {

String language = locale.getLanguage();

String country = locale.getCountry();

String localeString = null;

if (language != null) {

if (country != null) {

scanner.setLocale(language + "_" + country);

} else {

scanner.setLocale(language);

}

}

}

return scanner;

}

//扫描目录

private void scan(String[] directories, String volumeName) {

// don't sleep while scanning

mWakeLock.acquire();

ContentValues values = new ContentValues();

values.put(MediaStore.MEDIA_SCANNER_VOLUME, volumeName);

Uri scanUri = getContentResolver().insert(MediaStore.getMediaScannerUri(), values);

Uri uri = Uri.parse("file://" + directories[0]);

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri));

try {

if (volumeName.equals(MediaProvider.EXTERNAL_VOLUME)) {

openDatabase(volumeName);

}

MediaScanner scanner = createMediaScanner();

scanner.scanDirectories(directories, volumeName);

} catch (Exception e) {

Log.e(TAG, "exception in MediaScanner.scan()", e);

}

getContentResolver().delete(scanUri, null, null);

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri));

mWakeLock.release();

}

//扫描文件

private Uri scanFile(String path, String mimeType) {

String volumeName = MediaProvider.INTERNAL_VOLUME;

String externalStoragePath = Environment.getExternalStorageDirectory().getPath();

if (path.startsWith(externalStoragePath)) {

volumeName = MediaProvider.EXTERNAL_VOLUME;

openDatabase(volumeName);

}

MediaScanner scanner = createMediaScanner();

//扫描单个文件

return scanner.scanSingleFile(path, volumeName, mimeType);

}

在MediaProvider中还有一个类:MediaThumbRequest,用来创建预览图的,比如视频的预览图,图片的预览图,音频的专辑图片…这些图片的信息也是保存在数据库的,有兴趣的同学可以自己打开数据库看看里面的表。如下图:

media_db_tables

啰哩啰唆的写了两篇文章,希望对大家有所帮助。

其中应该有不少是错误的观点,望大家指正。

———————-END——————————

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏