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

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

转载请注明出处。

————–START————

MediaProvider包括五个类:

  • com.Android.providers.media.MediaProvider
  • com.Android.providers.media.MediaScannerCursor
  • com.Android.providers.media.MediaScannerReceiver
  • com.android.providers.media.MediaScannerService
  • com.android.providers.media.MediaThumbRequest

1.MediaProvider

此类继承ContentProvider,实现一个内容提供者。主要用于创建媒体库的数据库表。有自己创建过ContentProvider的同学相信都比较清楚的。

特别说明一下在MediaProvider中有个广播接收者,代码如下:

private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) {

// Remove the external volume and then notify all cursors backed by

// data on that volume

detachVolume(Uri.parse("content://media/external"));

sFolderArtMap.clear();

MiniThumbFile.reset();

}

}

};

此接收者是用来接收Sdcard卸载的广播。当Sdcard从手机中分离出来的时候,Sdcard中的媒体文件相对应的数据库将无法操作。

private void detachVolume(Uri uri) {

//判断是否是同一个进程

if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) {

throw new SecurityException(

"Opening and closing databases not allowed.");

}

//此方法只是操作Sdcard的媒体数据库,不支持手机内存的媒体数据库

String volume = uri.getPathSegments().get(0);

if (INTERNAL_VOLUME.equals(volume)) {

throw new UnsupportedOperationException(

"Deleting the internal volume is not allowed");

} else if (!EXTERNAL_VOLUME.equals(volume)) {

throw new IllegalArgumentException(

"There is no volume named " + volume);

}

synchronized (mDatabases) {

DatabaseHelper database = mDatabases.get(volume);

if (database == null) return;

try {

// touch the database file to show it is most recently used

File file = new File(database.getReadableDatabase().getPath());

file.setLastModified(System.currentTimeMillis());

} catch (SQLException e) {

Log.e(TAG, "Can't touch database file", e);

}

//移除数据库

mDatabases.remove(volume);

database.close();

}

getContext().getContentResolver().notifyChange(uri, null);

if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume);

注意移除数据库并非删除数据库文件(*.db),mDatabases是一个HashMap<String,DatabaseHelper>,移除的含义是暂时无法操作,也可以说说是查询返回的数据都是空的。

2.MediaScannerCursor

一个自定义游标,用来查询媒体文件的扫描状态。主要有一个volume字段,用来区分是内置媒体数据库还是Sdcard的媒体数据库。

3.MediaScannerReceiver

此类实现广播接收者。接收到广播的时候对手机的媒体文件进行扫描。

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/*Sdcard挂载广播*/) &amp;&amp;

externalStoragePath.equals(path)) {

scan(context, MediaProvider.EXTERNAL_VOLUME);

} else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE/*单个文件扫描广播*/) &amp;&amp;

path != null &amp;&amp; path.startsWith(externalStoragePath + "/")) {

scanFile(context, path);

}

}

}

}

扫描分为两种三种情况:

a,启动完毕扫面手机内存中的媒体文件

b.sdcard挂载完毕扫描扩展卡的媒体文件

c,扫描单个文件

应用实例:我们可以发送不同的广播让系统去扫描媒体文件。当需要扫描单个文件的时候需要设置一些参数,如下:


/**

* 扫描文件

*

* @param filePath 文件路径

* @author http://t.sina.com.cn/halzhang

*/

public void scanOneFile(final String filePath) {

Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

Uri uri = Uri.parse("file://" + filePath);

intent.setData(uri);

sendBroadcast(intent);

}

接着看一下scanscenFile两个方法:

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));

}

两个方法都是启动MediaScannerService去扫描媒体文件的。

关于MediaScannerSerive且听下回分解。

——————-END————–

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

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

支付宝扫一扫打赏

微信扫一扫打赏