您的位置:首页 > 移动开发 > Android开发

Android 系统提供媒体库 URI 与 数据库的对应关系

2017-02-27 15:52 423 查看
Android 系统提供媒体库 URI 与 数据库的对应关系
前言

MediaProvider
queryUri uri

getDatabaseForUriuri

Uri
URI_MATCHERaddURI

URI_MATCHERmatchuri

总结

附MediaStore Uri 与 数据库对应表仅供参考

Android 系统提供媒体库 URI 与 数据库的对应关系

前言

在 Android 系统中,本地媒体(e.g. 音乐)文件会被检索并且以
数据库
的形式进行保存管理,在开发 Android 程序的时候,我们可以使用
ContentProvider
设置
uri
去获取相关的数据1

在使用
ContentProvider
组件的时候,通常的做法是继承父类
ContentProvider
,然后重载父类中
inser()
delete()
update()
query()
等方法实现对数据的操作2

既然本地媒体文件在系统中是以
数据库
的形式来管理,并且提供了
uri
供我们使用,那么我猜在系统内部应该是有个
***Provider
的去实现对
数据库
的操作。

通过 Google 和 Baidu 找到了相关名词——
MediaProvider
,并且找到了源码3

MediaProvider

public class MeidaProvider extends ContentProvider {
private static final Uri MEDIA_URI = Uri.parse("content://media");
private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart");

...

}


我想这个
MeidaProvider.class
也许会给我们想要的线索,因为使用
ContentResolver
获取本地音乐中,使用的
uri
content://media/external/audio/media
,而这个
class
也出现了类似的字段。

MeidaProvider extends ContentProvider
那么应该会
重载 ContentProvider
的相关方法以向外提供数据操作方法。而在查询音乐数据使用的方法为
query(Uri uri, ...)
传入一个
uri
,所以先查看
query( )
的内容。

query(Uri uri, …)

//MediaProvider.class:1813
public Cursor query(Uri uri, String[] projectionIn, String selection, String[] selectionArgs, String sort) {
int table = URI_MATCHER.match(uri);

...

String groupBy = null;
DatabaseHelper helper = getDatabaseForUri(uri);

...

switch (table) {

...

case AUDIO_MEDIA:
if (projectionIn != null && projectionIn.length == 1 &&  selectionArgs == null
&& (selection == null || selection.equalsIgnoreCase("is_music=1")
|| selection.equalsIgnoreCase("is_podcast=1") )
&& projectionIn[0].equalsIgnoreCase("count(*)")
&& keywords != null) {
//Log.i("@@@@", "taking fast path for counting songs");
qb.setTables("audio_meta");
} else {
qb.setTables("audio");
for (int i = 0; keywords != null && i < keywords.length; i++) {
if (i > 0) {
qb.appendWhere(" AND ");
}
qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY +
"||" + MediaStore.Audio.Media.ALBUM_KEY +
"||" + MediaStore.Audio.Media.TITLE_KEY + " LIKE ? ESCAPE '\\'");
prependArgs.add("%" + keywords[i] + "%");
}
}
break;
case AUDIO_MEDIA_ID:
qb.setTables("audio");
qb.appendWhere("_id=?");
prependArgs.add(uri.getPathSegments().get(3));
break;

...

}

//MediaProvider.class:4716
static
{
...

URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA);
URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID);
URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES);

...
}


从以上代码可以看出,在
query( )
中,使用
URI_MATCHER.match(uri)
对传入的
uri
进行解析,然后在
switch( )
setTables( )
设置对应的表或者视图。

getDatabaseForUri(uri);

//MediaProvider.java:4456
private DatabaseHelper getDatabaseForUri(Uri uri) {
synchronized (mDatabases) {
if (uri.getPathSegments().size() >= 1) {
return mDatabases.get(uri.getPathSegments().get(0));
}
}
return null;
}

//MediaProvider.java:4490
private Uri attachVolume(String volume) {
//将 “db” 路径判断存入 “mDatabases”
}


MediaProvider.onCrearte()
被创建启动的时候会查看是否有外置存储器,并执行
attachVolume()
方法(:508),将内外置存储器中的数据库路径存入
mDatabases


Uri

通用资源标识符(Uniform Resource Identifier)4

URI是一个用于标识某一互联网资源名称的字符串。 该种标识允许用户对任何(包括本地和互联网)的资源通过特定的协议进行交互操作。在ContentProvider机制中,使用ContentResolver对象通过URI定位ContentProvider提供的资源。

ContentProvider使用的URI语法结构如下:

content://<authority>/<data_path>/<id>


content:// 是通用前缀,表示该UIR用于ContentProvider定位资源。

< authority > 是授权者名称,用来确定具体由哪一个ContentProvider提供资源。因此一般< authority >都由类的小写全称组成,以保证唯一性。

< data_path > 是数据路径,用来确定请求的是哪个数据集。如果ContentProvider近提供一个数据集,数据路径则可以省略;如果ContentProvider提供多个数据集,数据路径必须指明具体数据集。数据集的数据路径可以写成多段格式,例如people/girl和people/boy。

< id > 是数据编号,用来唯一确定数据集中的一条记录,匹配数据集中_ID字段的值。如果请求的数据不只一条,< id >可以省略。

如请求整个people数据集的URI为:

content://com.example.peopleprovider/people


而请求people数据集中第3条数据的URI则应写为:

content://com.example.peopleprovider/people/3


URI_MATCHER.addURI( );

Add a URI to match, and the code to reutrn when this URI is matched. URI nodes may be exact match string, the token “*” that matches any text, or the token “#” that matches only numbers.5

//MediaProvider.class:4716
static
{
...

URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA);
URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID);
URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES);

...
}


添加
uri
匹配对应关系。

第二个参数
"*/audio/media"
中的 “*” 给
internal
external
预留位置,用于指明访问的数据库位于 内置存储器 或是 外置存储器

URI_MATCHER.match(uri);

源码使用了
UriMatch
对传入的
uri
进行匹配。

总结

MediaProvider
本质上就是一个
Provider
,用过
ContentProvider
去理解应该不难。

附:MediaStore Uri 与 数据库对应表(仅供参考)

URI (content://media/external/audio/)Table \ View (external.db)
media (specific)audio_meta
media (all) & media/#audio
media/#/genres & media/#/genres/#audio_genres
media/#/playlists & media/#/playlists/#audio_playlists
genres & genres/#audio_genres
genres/#/membersaudio_genres_map_noid
genres/all/membersaudio_genres_map_noid
playlists & playlists/#audio_playlists
playlists/#/members & playlists/#/members/#audio_playlists_map
artists (specific)audio_meta
artists (all) & artists/#artist_info
artists/#/albums[多张表联合]
albums (specific)audio_meta
albums (all) & albums/#album_info
albumart/#album_art
P. S.
MediaProvider.class
比较大,下载下来之后,放到
Android Studio
上可以方便查看代码。



Android中利用ContentResolver获取本地音乐和相片
Android ContentProvider 完全解析及简单DEMO
MeidaProvider 源码(需梯子)
Android ContentProvider 完全解析及简单DEMO
UriMatcher | Android Developers
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: