讀古今文學網 > Android程序設計:第2版 > 文件管理和二進制數據 >

文件管理和二進制數據

內容提供者通常需要管理大量的二進制數據,如位圖或音樂剪輯。應用的設計中需要對大數據文件的存儲有充分考量,否則可能會有嚴重的性能問題。內容提供者可以通過內容提供者URI提供文件服務,該URI中封裝了實際物理文件的位置,因此客戶端不知道該信息。使用內容提供者URI來訪問文件的客戶端不知道這些文件的真正存儲方式。這種中間層使得內容提供者管理文件的方式很合理,而且不會把信息暴露給客戶端——否則如果內容提供者需要改變物理文件的存儲方式,還需要客戶端代碼也要進行相應修改。通常來說,只改變提供者代碼而不需要其所有的客戶端修改,這樣事情就簡單得多。客戶端不需要知道一組提供者媒體文件是保存在閃存卡、SD卡還是網絡上,只要該提供者支持從一組內容提供者中訪問文件即可。對於給定的URI,客戶端只需要調用ContentResolver.openInputStream方法並從結果流中讀取數據。

此外,因為Android應用不應該讀寫其他應用創建的文件,所以,當應用之間共享大量數據時也必須使用內容提供者來訪問相關的數據。因此,當第一個內容提供者返回文件指針,這個指針必須是content://URI形式,而不是Unix文件名形式。使用content://URI打開文件,並由擁有該文件的讀權限的內容提供者執行讀操作,而不是客戶端應用直接執行(客戶端應用不應該有訪問文件的權限)。

處理文件系統的I/O操作要比處理SQLite的blob數據快得多,而且功能也更強大,但使用Unix文件系統直接存儲二進制數據是更好的方式。此外,把二進制數據放在數據庫中沒有什麼優勢,因為你無法查詢這些數據。

為了在應用中實現文件讀寫,Android SDK文檔建議使用內容提供者把數據保存到文件中,並在數據庫中存儲指向該文件的content://URI,如圖12-2所示。客戶端應用會傳遞這個字段中的URI給ContentProvider.openStream方法,然後從指定的文件中檢索二進制流。

圖12-2:Android MVC典型的光標和內容提供者的使用

具體而言,建議使用文件,而不是創建一個類似下面這樣的用戶表:


CREATE TABLE user ( _id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, password
                              TEXT, picture BLOB );
  

Google Android文檔建議創建如下兩張表:


CREATE TABLE user ( _id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, password
                              TEXT, picture TEXT );
CREATE TABLE userPicture ( _id INTEGER PRIMARY KEY AUTOINCREMENT,
                              _data TEXT );
  

user表的picture字段會保存指向userPicture表的一條記錄的content://URI。userPicture表的_data字段會指向Android文件系統中的真正文件。

如果該文件的路徑直接保存在user表中,則客戶端會直接得到這個路徑,但是無法打開文件,因為這個文件屬於為應用提供服務的內容提供者,用戶沒有權限訪問它。但是,在這裡給出的解決方案中,訪問權限是由ContentResolver類控制的,稍後將對這個類進行介紹。

當處理請求時,ContentResolver類會查找_data字段中存儲的文件,如果找到了相應的文件,提供者的openOutputStream方法會打開這個文件,並返回java.io.OutputStream給客戶端。即使客戶端能夠直接打開文件,返回的仍然是這個對象。ContentResolver類屬於內容提供者所在的應用,因此雖然客戶端無法打開文件,但ContentResolver類是可以打開文件的。

在本章的後面,將介紹一種內容提供者,其功能是使用內容提供者文件管理工具保存縮略圖。