`

Android media媒体库分析之:MediaProvider

 
阅读更多
亲们,原创文章转载时请注明出处,谢谢!
在做Android媒体应用程序时(Audio、Image、Video)需要对Android的媒体提供者(MediaProvider)做详细的分析,下面记录一下我的收获:

一、获取MediaProvider:
该工程在系统源码的packages\providers目录下,提出并导入Eclipse,便于阅读;



图中可见都很多报错的,是滴,因为需要一些系统标准sdk之外的接口,不过不影响我们阅读代码。

二、工程结构及内部关系:
可以从上图看出包含4个文件:
MediaScannerService.Java:媒体服务,配合广播实现媒体扫描类的实例化,数据库的初始化等工作,也向外提供接口;
MediaScannerReceiver.Java:一个广播接收器,用于接受系统发给媒体服务的广播并启动媒体服务;
MediaProvider.Java:媒体数据库的封装类,代码量比较大(四千多行),功能比较复杂,但总的来说就是创建数据库,对外提供URI以实现对数据库的增删改查功能;
MediaThumbRequest.Java:媒体文件缩略图请求类,与MediaProvider配合使用;
上一个关系图更直观一些:



上图不是标准的类图,只是为了梳理逻辑关系画的结构图。
MediaProvider所处的位置及作用见图中红色框中的内容;
上图还包括其他内容:
1、App层:audio、image、video如何与媒体库进行交互;
2、框架层(android.media包下):如何实现媒体的扫描;
3、Native层:如何实现正在的媒体文件解析;
4、资源存储层:sd卡、U盘等介质,DTCM存储缩略图;

三、类详解

1、MediaScannerReceiver:
	public void onReceive(Context context, Intent intent) {
		String action = intent.getAction();
		Uri uri = intent.getData();
		// String externalStoragePath =
		// Environment.getExternalStorageDirectory().getPath();
		String externalSDStoragePath = Environment
				.getExternalSDStorageDirectory().getPath();
		String externalUDiskStoragePath = Environment
				.getExternalUDiskStorageDirectory().getPath();
		String externalExtSDStoragePath = Environment
				.getExternalExtSDStorageDirectory().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)) {
					if (externalSDStoragePath.equals(path))
						scan(context, MediaProvider.EXTERNAL_VOLUME_SD);
					else if (externalUDiskStoragePath.equals(path))
						scan(context, MediaProvider.EXTERNAL_VOLUME_UDISK);
					else if (externalExtSDStoragePath.equals(path))
						scan(context, MediaProvider.EXTERNAL_VOLUME_EXTSD);
					else
						Slog.w(TAG, "unknown volume path " + path);
				} else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
						&& path != null
						&& (path.startsWith(externalSDStoragePath + "/")
								|| path.startsWith(externalExtSDStoragePath
										+ "/") || path
									.startsWith(externalUDiskStoragePath + "/"))) {
					scanFile(context, path);
				}
			}
		}
	}

三类情况需要启动扫描服务:
a、系统启动完成;
b、媒体挂载(EXTERNAL_VOLUME_SD、EXTERNAL_VOLUME_UDISK、EXTERNAL_VOLUME_EXTSD);
c、媒体文件扫描广播(ACTION_MEDIA_SCANNER_SCAN_FILE);

scanFile和scan方法很简单,只是启动媒体服务即可:
	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();
		Slog.i(TAG, "Start scanFile.");
		args.putString("filepath", path);
		context.startService(new Intent(context, MediaScannerService.class)
				.putExtras(args));
	}


2、MediaScannerService:
第一步:启动一个线程
	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();
	}

在线程中拿到当前的消息队列,使用handler处理消息;

第二部:启动ServiceHandler处理消息
ServiceHandler中还是处理两种,一种是扫描,第二种是具体媒体文件的解析;
看一下第二种是如何实现的:
					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);
					}


	private final IMediaScannerService.Stub mBinder = new IMediaScannerService.Stub() {
		public void requestScanFile(String path, String mimeType,
				IMediaScannerListener listener) {
			if (Config.LOGD) {
				Log.d(TAG, "IMediaScannerService.scanFile: " + path
						+ " mimeType: " + mimeType);
			}
			Bundle args = new Bundle();
			args.putString("filepath", path);
			args.putString("mimetype", mimeType);
			if (listener != null) {
				args.putIBinder("listener", listener.asBinder());
			}
			startService(new Intent(MediaScannerService.this,
					MediaScannerService.class).putExtras(args));
		}

		public void scanFile(String path, String mimeType) {
			requestScanFile(path, mimeType, null);
		}
	};


那么问题来了:如果我们在App中想让系统媒体库解析具体某一个文件,应该怎么做呢?
从上面代码可以看到,MediaScannerService给我们提供的绑定接口,我们只需要传递filepath和一个IMediaScannerListener listener即可,媒体库在解析完之后会回调scanCompleted方法告诉我们解析结果;

第三步:创建MediaScanner对象,完成扫描和解析;
可见具体扫描、解析工作也不是MediaScannerService做的,MediaScannerService是只在调用sacn、acanfile方法时创建了MediaScanner对象并交给他处理;
MediaScanner在android.media.MediaScanner系统framework里面,这儿就不做讨论了;

MediaScannerService基本就这些内容了;

3、MediaProvider:
MediaProvider就是创建数据库,对外提供URI以实现对数据库的增删改查功能;

4、MediaThumbRequest:
Audio、Image、Video文件都是有缩略图的,缩略图路径存储在DB中,其真实文件存储在sd卡的DICM文件夹下,MediaThumbRequest只是提供给MediaProvider类操作数据库使用。
主要的就两个方法,一个新建缩略图方法:execute,一个更新缩略图方法:updateDatabase
新技能get:应用中获取缩略图,期待下一篇文章;

至此,MediaProvider结构分析清楚了,后续计划补两片文章:
APP中使用系统媒体库;
媒体文件扫描、解析是如何实现的;
  • 大小: 15.3 KB
  • 大小: 259.4 KB
0
0
分享到:
评论
1 楼 麦田的设计者 2016-08-25  

相关推荐

    android MediaProvider和MediaScanner详解

    在实际开发中,开发者可能需要与MediaProvider和MediaScanner组件交互,比如在开发音乐播放器或图片查看器时,这些应用会依赖于MediaProvider提供的内容,而MediaScanner则在背后默默地更新媒体库。因此,了解这些...

    android mediaScannder框架介绍

    Android多媒体扫描框架,即Media Scanner,是Android系统中用于检测和处理...当有新的媒体文件出现或已有的文件发生变化时,Media Scanner通过接收广播意图并进行扫描,确保媒体库始终与实际存储的媒体文件保持同步。

    Android媒体库框架(mediascanner).doc

    Android 媒体库框架(MediaScanner) Android 媒体库框架(MediaScanner)是 Android 平台上的一种媒体文件管理机制,旨在提供一个统一的媒体文件管理方式,帮助用户快速地浏览和管理媒体文件。 媒体文件管理机制 ...

    Android中扫描多媒体文件操作详解

    在Android系统中,多媒体文件的管理与访问是一个关键部分,涉及到用户媒体库的更新和同步。本文将深入探讨Android中的多媒体文件扫描机制,以及如何在应用程序中操作这些文件。 首先,Android通过`MediaProvider`来...

    Android4.4下MediaProvider无法向外置SD卡中文件写数据的解决方法

    6. 对于需要写入特定媒体类型的文件,可以使用`MediaScannerConnection`扫描新创建的文件,使其出现在系统的媒体库中。 7. 在处理文件流时,确保正确关闭`OutputStream`,避免资源泄漏。 总之,解决Android 4.4下...

    Android多媒体扫描过程.pdf

    - 扫描过程中,MediaScanner会更新SQLite数据库中的媒体信息,包括文件路径、元数据、时间戳等,使得媒体库保持最新状态。 综上所述,Android多媒体扫描过程是一个涉及多层交互、文件类型识别、元数据提取和服务...

    Android获取相册图片-实现选择相册图片功能

    MediaProvider是Android系统提供的一种服务,它将媒体库中的内容组织成一个可以被其他应用访问的数据集。通过特定的URI,我们可以获取到MediaProvider中的不同类型的媒体资源。对于图片,我们可以使用`MediaStore....

    Android多媒体扫描过程[参考].pdf

    扫描完成后,系统会更新媒体库,使得用户可以在音乐、视频或图片应用中看到新扫描到的媒体文件。 9. **性能优化**: 为了提高性能,扫描过程可能涉及缓存技术,以减少对数据库的直接访问。同时,通过JNI(Java ...

    Android源码下载 cmd

    - `git clone git://android.git.kernel.org/platform/packages/providers/MediaProvider.git platform/packages/providers/MediaProvider` - 媒体资源管理服务。 #### 三、执行步骤 1. **切换到工作目录:** -...

    android_APK文件对照

    - **可否删除**:如果用户不使用媒体库功能,可以删除。 51. **MediaProvider.apk** - **功能描述**:提供媒体数据的服务。 - **可否删除**:不建议删除,涉及到媒体文件管理。 52. **MediaSync.apk** - **...

    完美解决android M上锁屏情况下,禁止pc通过MTP访问手机存储单元

    首先,我们要关注的关键文件是`/m8976/packages/providers/MediaProvider/src/com/android/providers/media/MtpService.java`。在这个文件中,我们找到`updateDisabledStateLocked`方法。这个方法负责控制MTP服务...

Global site tag (gtag.js) - Google Analytics