Android MediaProvider数据库模式

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介:

Android MediaProvider数据库模式

原文地址

摘要: Android MediaProvider 使用 SQLite 数据库存储图片、视频、音频等多媒体文件的信息,供视频播放器、音乐播放器、图库使用。本文详细分析了 Android MediaProvider 多媒体数据库(以 SDK 2.3.3 为例)的模式(schema),并简要叙述与系统媒体扫描服务 MediaScanner 的交互。

 

1. 如何提取数据库

以 root 权限进入 adb shell,使用 sqlite3 打开位于手机上 /data/data/com.android.providers.media/databases 上的一个数据库。以 external 开头的数据库存储的是 SD 卡媒体信息,一张卡对应一个,所以如果手机使用过多张卡会有多个数据库。以 internal 开头的数据库存储手机内部存储器的媒体信息。因为一般用户无法访问手机内部存储器,而且这两个数据库结构是大体上是相同的,所以只需要关注 external 数据库即可。

Note: 数据库都是以类似 external-ffffffff.db 的形式命名的, 后面的 8 个 16 进制字符是该 SD 卡 FAT 分区的 Volume ID。该 ID 是分区时决定的,只有重新分区或者手动改变才会更改,可以防止插入不同 SD 卡时数据库冲突。要简单了解 FAT 文件系统请看 Understanding FAT Filesystems

接着在 sqlite3 执行命令 .schema 即可导出创建数据库的 SQL 语句,也就是数据库模式,具体如下(单击展开代码):

 

Note: 如果手机没有 sqlite3 程序,可以搜索编译过的源代码的 out 目录找到可执行文件,大约 90kb,然后 adb push 到手机的 /system/bin/ 目录。安装 sqlite3、查询数据库均需要 adb root 权限。 Android 的多媒体数据库主要由表、视图、索引以及触发器组成。

接着还需要把数据库转换成图,手工转换的话就是根据 SQL 语句自行画图;推荐懒人使用自动转换,先使用 adb pull 把数据库导出,再使用 Power Designer 或者 Visio 的逆向工程(Reverse Engineer)功能生成物理数据模型(Physical Data Model)。注意要连接 sqlite 数据库文件的话需要先安装 sqlite 的 ODBC 驱动,教程在这里:SQLite ODBC Driver

2. 数据库模式分析

图片数据库

图片数据库由两个表组成,分别是 images 和 thumbnails,物理数据模型如下所示(Power Designer 逆向工程生成)

Note: 如何数据库物理模型图:<pk> 表示此为主键。其余的表名、字段名、数据类型应该都能看明白。

Note: SQLite 从 3.6.19 版才开始支持外键约束,Android 2.3.3 使用的是 3.7.x,但并没有使用此特性,而是通过操作数据库的程序(如 MediaScanner)以及触发器来维护数据库的一致性。这里可以了解 SQLite 的外键支持情况

数据表字段解析如下:

images:图片信息  
字段 解析
_id 主键。图片 id,从 1 开始自增
_data 图片绝对路径
_size 文件大小,单位为 byte
_display_name 文件名
mime_type 类似于 image/jpeg 的 MIME 类型
title 不带扩展名的文件名
date_added 添加到数据库的时间,单位秒
date_modified 文件最后修改时间,单位秒
description  
picasa_id 用于 picasa 网络相册
isprivate  
latitude 纬度,需要照片有 GPS 信息
longitude 经度,需要照片有 GPS 信息
datetaken 取自 EXIF 照片拍摄时间,若为空则等于文件修改时间,单位毫秒
orientation 取自 EXIF 旋转角度,在图库旋转图片也会改变此值
mini_thumb_magic 取小缩略图时生成的一个随机数,见 MediaThumbRequest
bucket_id 等于 path.toLowerCase.hashCode(),见 MediaProvider.computeBucketValues()
bucket_display_name 直接包含图片的文件夹就是该图片的 bucket,就是文件夹名
thumbnails:缩略图  
字段 解析
_id 主键。缩略图 id,从 1 开始自增
_data 图片绝对路径
image_id 缩略图所对应图片的 id,依赖于 images 表 _id 字段,可建立外键
kind 缩略图类型,1 是大缩略图,2 基本不用,3 是微型缩略图但其信息不保存在数据库
width 缩略图宽度
height 缩略图高度

视频数据库

数据表字段解析如下:

video:视频信息  
字段 解析
_id 主键。视频 id
_data 视频绝对路径
_display_name 文件名
_size 文件大小,单位为 byte
mime_type 类似于 video/avi 的 MIME 类型
date_added 添加到数据库的时间,单位秒
date_modified 文件最后修改时间,单位秒
title 不带扩展名的文件名
duration 视频时长,单位毫秒
artist 艺术家
album 专辑名,一般为文件夹名
resolution  
description  
isprivate  
tags  
category  
language  
mini_thumb_data  
latitude  
longitude  
datetaken  
mini_thumb_magic 取小缩略图时生成的一个随机数,见 MediaThumbRequest
bucket_id 等于 path.toLowerCase.hashCode(),见 MediaProvider.computeBucketValues()
bucket_display_name 直接包含视频的文件夹就是该图片的 bucket,就是文件夹名
bookmark  
videothumbnails:视频缩略图  
字段 解析
_id 主键。缩略图 id
_data 缩略图绝对路径
video_id 缩略图所对应视频的 id,依赖于 video 表 _id 字段
kind 缩略图类型,1 是大图,视频只能取类型 1
width 缩略图宽度
height 缩略图高度

音频数据库

音频数据库是最复杂的,由 10 个表组成。物理数据模型如下所示:

album_art:专辑封面  
字段 解析
album_id 主键。专辑 id
_data 专辑封面缓存的路径
albums:专辑信息  
字段 解析
album_id 主键。专辑 id
album_key 全大写字母,用于字母索引
album 专辑名
android_metadata:当前字符编码  
字段 解析
locale 默认字符编码,例如 zh_CN
artists:艺术家  
字段 解析
artist_id 主键。艺术家 id
artist_key 全大写字母,用于字母索引
artist 艺术家
audio_genres:流派  
字段 解析
_id 主键。流派 id
name 流派名称
audio_genres_map:音频流派映射  
字段 解析
_id 主键。映射 id
audio_id 音频 id
genre_id 流派 id

Note: 为何要建立映射表:为了消除数据冗余。假如有大量音频属于同一流派,如果没有映射表则需要每个音频都需要记录同样的流派数据,有了映射表之后则只有一条记录就够了。这符合数据库设计的第三范式(the 3rd normal form)

audio_meta:音频信息  
字段 解析
_id 主键。音频 id
_data 文件绝对路径
_display_name 文件名
_size 文件大小,单位 byte
mime_type 类似于 audio/mpeg 的 MIME 类型
date_added 添加到数据库的时间,单位秒
date_modified 文件最后修改时间,单位秒
title 来自 ID3 信息的标题,无则为不带扩展名的文件名
title_key 全大写字母的标题
duration 时长
artist_id 艺术家 id
composer 来自 ID3 信息,作曲家
album_id 专辑 id
track 来自 ID3 信息,音轨
year 来自 ID3 信息,年代
is_ringtone 是否铃声,0 或 1
is_music 是否音乐,1 才会在音乐播放器显示
is_alarm 是否闹钟铃声
is_notification 是否通知铃声
is_podcast 是否 podcast
bookmark  
audio_playlists:播放列表  
字段 解析
_id 主键。播放列表 id
_data  
name 播放列表名
date_added  
date_modified  
audio_playlists_map:音频播放列表映射  
字段 解析
_id 主键。映射 id
audio_id 音频 id
playlist_id 播放列表 id
play_order 播放顺序

索引

在 Android 数据库当中基本上使用自增 id 值作为主键,并建立了索引。索引可以加快数据查找速度,但由于需要维护索引所以插入/删除等写入操作速度会变慢。索引如下:

1 CREATE INDEX album_id_idx on audio_meta(album_id);
2 CREATE INDEX album_idx on albums(album);
3 CREATE INDEX albumkey_index on albums(album_key);
4 CREATE INDEX artist_id_idx on audio_meta(artist_id);
5 CREATE INDEX artist_idx on artists(artist);
6 CREATE INDEX artistkey_index on artists(artist_key);
7 CREATE INDEX image_bucket_index ON images(bucket_id, datetaken);
8 CREATE INDEX image_id_index on thumbnails(image_id);
9 CREATE INDEX sort_index on images(datetaken ASC, _id ASC);
10 CREATE INDEX title_idx on audio_meta(title);
11 CREATE INDEX titlekey_index on audio_meta(title_key);
12 CREATE INDEX video_bucket_index ON video(bucket_id, datetaken);
13 CREATE INDEX video_id_index on videothumbnails(video_id);

由于比较简单就不解释了,要深入了解索引可以参考这个关于 SQL Server 的分析MySQL索引背后的数据结构及算法原理,原理应该是差不多的。

视图

视图类似于表,但并非独立存在,是从其他表里面查询数据得到的。使用视图可以加快数据库查询速度,不用每次都执行复杂的 SQL 语句查询。图如下所示:

Note: 如何看视图:图下面的部分是数据来源的表,中间是从表中选取的字段,但类似于 COUNT 等 SQL 查询操作无法在图上体现,最好还是看实际 SQL 语句。

Note: SQLite 当中视图都是只读的,也就是说不能对视图进行插入、更新、删除等操作。但是可以在视图建立 INSTEAD OF 触发器来达到同样的目的,多媒体数据库当中的 audio_delete 触发器就是如此。

触发器

触发器是为了维护数据库删除操作而建立的,因为所删除的表可能与另外的表有关系,需要同时删除另外一个表的字段。可以看以下一个例子:

1 CREATE TRIGGER audio_meta_cleanup
2 DELETE ON audio_meta
3 BEGIN
4     DELETE FROM audio_genres_map WHERE audio_id = old._id;
5     DELETE FROM audio_playlists_map WHERE audio_id = old._id;
6 END;

这是关于 audio_meta 表的触发器,意思是当删除此表上的记录时,同时删除 audio_genres_map 表上 audio_id 与此表 id 相同的记录,删除 audio_playlists_map 表上 audio_id 与此表 id 相同的记录。这样当删除 audio_meta 表的记录时,另外两个表的相应记录也会自动删除,不会由于漏删除而残留多余数据。

3. 如何维护数据库

插入

插入、更新主要由 MediaScanner 进行,当删除/移动媒体文件时 MediaScanner 会扫描磁盘并更新数据库。数据插入主要在 endFile() 方法中进行,例如插入音频记录时相关的表都会插入相应的记录。而图片、视频缩略图,专辑封面这几个则是第一次取图片的时候才会生成缩略图保存到磁盘,并把记录插入到数据库中。

删除

删除操作主要由触发器维护。例如当一个应用删除图片时,一般只会删除图片数据库,所以必须要有触发器同时删除缩略图数据库。



本文转自Work Hard Work Smart博客园博客,原文链接:http://www.cnblogs.com/linlf03/p/3477077.html,如需转载请自行联系原作者

目录
相关文章
|
4月前
|
设计模式 Android开发 Kotlin
Android经典实战之Kotlin委托模式和by关键字
本文介绍了Kotlin中`by`关键字在类及属性委托中的运用,通过实例展示了如何利用类委托简化接口实现,以及如何借助标准与自定义属性委托管理属性的读写操作。通过`by`关键字的支持,Kotlin使得委托模式的实现更为直观且高效。
89 4
|
4月前
|
资源调度 关系型数据库 MySQL
【Flink on YARN + CDC 3.0】神操作!看完这篇教程,你也能成为数据流处理高手!从零开始,一步步教会你在Flink on YARN模式下如何配置Debezium CDC 3.0,让你的数据库变更数据瞬间飞起来!
【8月更文挑战第15天】随着Apache Flink的普及,企业广泛采用Flink on YARN部署流处理应用,高效利用集群资源。变更数据捕获(CDC)工具在现代数据栈中至关重要,能实时捕捉数据库变化并转发给下游系统处理。本文以Flink on YARN为例,介绍如何在Debezium CDC 3.0中配置MySQL连接器,实现数据流处理。首先确保YARN上已部署Flink集群,接着安装Debezium MySQL连接器并配置Kafka Connect。最后,创建Flink任务消费变更事件并提交任务到Flink集群。通过这些步骤,可以构建出从数据库变更到实时处理的无缝数据管道。
319 2
|
4月前
|
存储 SQL 算法
【OceanBase】惊天大反转!启动时真的会占用95%磁盘空间?别怕!揭秘真相+实用调整技巧,手把手教你如何优雅地管理磁盘空间,让你的数据库从此告别“吃土”模式!
【8月更文挑战第15天】OceanBase是一款高性能分布式数据库,启动时并不会默认占用95%磁盘空间,这是一种误解。其设计注重资源管理,可根据业务需求动态调整空间使用。通过设置`max_disk_usage`等参数、优化表设计、定期清理数据及启用压缩等功能,可有效控制磁盘占用,确保高效利用存储资源。
89 1
|
4月前
|
SQL 数据库 Java
Hibernate 日志记录竟藏着这些秘密?快来一探究竟,解锁调试与监控最佳实践
【8月更文挑战第31天】在软件开发中,日志记录对调试和监控至关重要。使用持久化框架 Hibernate 时,合理配置日志可帮助理解其内部机制并优化性能。首先,需选择合适的日志框架,如 Log4j 或 Logback,并配置日志级别;理解 Hibernate 的多级日志,如 DEBUG 和 ERROR,以适应不同开发阶段需求;利用 Hibernate 统计功能监测数据库交互情况;记录自定义日志以跟踪业务逻辑;定期审查和清理日志避免占用过多磁盘空间。综上,有效日志记录能显著提升 Hibernate 应用的性能和稳定性。
51 0
|
4月前
|
SQL API 数据库
揭秘Ruby数据库交互的黑科技!ActiveRecord模式:为何它让数据库操作如此“随心所欲”?
【8月更文挑战第31天】在Ruby编程中,与数据库交互至关重要。ActiveRecord作为Ruby on Rails框架的核心组件,凭借其简洁高效的特点,成为处理数据库操作的首选。本文深入探讨ActiveRecord模式,介绍其如何简化数据库交互,并通过示例代码展示具体应用。ActiveRecord是一种ORM框架,将数据库表映射为Ruby类,使开发者能通过操作对象间接管理数据库记录。其核心特性包括模型定义、关联管理、数据验证、事务处理及强大的查询接口。通过示例代码,展示了如何定义模型、创建记录、查询记录及处理关联,突显了ActiveRecord在简化数据库操作方面的优势。
70 0
|
5月前
|
存储 前端开发 测试技术
Android Kotlin中使用 LiveData、ViewModel快速实现MVVM模式
使用Kotlin实现MVVM模式是Android开发的现代实践。该模式分离UI和业务逻辑,借助LiveData、ViewModel和DataBinding增强代码可维护性。步骤包括创建Model层处理数据,ViewModel层作为数据桥梁,以及View层展示UI。添加相关依赖后,Model类存储数据,ViewModel类通过LiveData管理变化,而View层使用DataBinding实时更新UI。这种架构提升代码可测试性和模块化。
187 2
|
6月前
|
存储 关系型数据库 数据库
回顾数据库的三级模式,为什么比直接存文件表格好?
【6月更文挑战第10天】本文介绍数据库用于解决Excel等文件系统存在的数据冗余、不一致和访问困难等问题。DBMS中的关系有一对一、一对多、多对一和多对多四种类型。键有候选键、超级键、主键、备用键和外键等类型,功能依赖分为平凡和非平凡两种。
44 0
回顾数据库的三级模式,为什么比直接存文件表格好?
|
6月前
|
数据库 Android开发 数据安全/隐私保护
在 Android Studio 中结合使用 SQLite 数据库实现简单的注册和登录功能
在 Android Studio 中结合使用 SQLite 数据库实现简单的注册和登录功能
247 2
|
6月前
|
存储 NoSQL 算法
图数据库:连接数据的新模式
【6月更文挑战第16天】图数据库是处理复杂关系数据的新兴技术,使用节点、边和属性表示数据间关系。它提供强大的关系表达能力、灵活性、实时性和扩展性。新模式包括关系网络可视化、基于路径的查询、内置图算法支持,适用于推荐系统和社交网络分析,助力企业挖掘数据价值并应对大数据时代挑战。随着技术发展,图数据库将在数据连接和分析中扮演关键角色。
|
6月前
|
关系型数据库 数据库