Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android MediaProvider數據庫模式

Android MediaProvider數據庫模式

編輯:關於Android編程

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: 如何數據庫物理模型圖: 表示此為主鍵。其余的表名、字段名、數據類型應該都能看明白。

Note: SQLite 從 3.6.19 版才開始支持外鍵約束,但並沒有使用此特性,而是通過操作數據庫的程序(如 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 CREATEINDEXalbum_id_idxonaudio_meta(album_id); 2 CREATEINDEXalbum_idxonalbums(album); 3 CREATEINDEXalbumkey_indexonalbums(album_key); 4 CREATEINDEXartist_id_idxonaudio_meta(artist_id); 5 CREATEINDEXartist_idxonartists(artist); 6 CREATEINDEXartistkey_indexonartists(artist_key); 7 CREATEINDEXimage_bucket_indexONimages(bucket_id, datetaken); 8 CREATEINDEXimage_id_indexonthumbnails(image_id); 9 CREATEINDEXsort_indexonimages(datetakenASC, _idASC); 10 CREATEINDEXtitle_idxonaudio_meta(title); 11 CREATEINDEXtitlekey_indexonaudio_meta(title_key); 12 CREATEINDEXvideo_bucket_indexONvideo(bucket_id, datetaken); 13 CREATEINDEXvideo_id_indexonvideothumbnails(video_id);

由於比較簡單就不解釋了,要深入了解索引可以參考這個關於 SQL Server 的分析MySQL索引背後的數據結構及算法原理,原理應該是差不多的。

視圖

視圖類似於表,但並非獨立存在,是從其他表裡面查詢數據得到的。使用視圖可以加快數據庫查詢速度,不用每次都執行復雜的 SQL 語句查詢。圖如下所示:

 

Note: 如何看視圖:圖下面的部分是數據來源的表,中間是從表中選取的字段,但類似於 COUNT 等 SQL 查詢操作無法在圖上體現,最好還是看實際 SQL 語句。

Note: SQLite 當中視圖都是只讀的,也就是說不能對視圖進行插入、更新、刪除等操作。但是可以在視圖建立INSTEAD OF 觸發器來達到同樣的目的,多媒體數據庫當中的 audio_delete 觸發器就是如此。

觸發器

觸發器是為了維護數據庫刪除操作而建立的,因為所刪除的表可能與另外的表有關系,需要同時刪除另外一個表的字段。可以看以下一個例子:

1 CREATETRIGGERaudio_meta_cleanup 2 DELETEONaudio_meta 3 BEGIN 4 DELETEFROMaudio_genres_mapWHEREaudio_id = old._id; 5 DELETEFROMaudio_playlists_mapWHEREaudio_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() 方法中進行,例如插入音頻記錄時相關的表都會插入相應的記錄。而圖片、視頻縮略圖,專輯封面這幾個則是第一次取圖片的時候才會生成縮略圖保存到磁盤,並把 記錄插入到數據庫中。

刪除

刪除操作主要由觸發器維護。例如當一個應用刪除圖片時,一般只會刪除圖片數據庫,所以必須要有觸發器同時刪除縮略圖數據庫。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved