容提供器用來存放和擷取資料並使這些資料可以被所有的應用程式訪問。它們是應用程式之間共用資料的唯一方法;不存在所有Android軟體包都能訪問的公用儲存地區。
Android為常見資料類型(音頻,視頻,映像,個人連絡人資訊,等等)裝載了很多內容提供器。你可以看到在android.provider包裡列舉了一些。你還能查詢這些提供器包含了什麼資料(儘管,對某些提供器,你必須擷取合適的許可權來讀取資料)。
如果你想公開你自己的資料,你有兩個選擇:你可以建立你自己的內容提供器(一個ContentProvider子類)或者你可以給已有的提供器添加資料-如果存在一個控制同樣類型資料的內容提供器且你擁有寫的許可權。
這篇文檔是一篇關於如何使用內容提供器的簡介。先是一個簡短的基礎知識討論,然後探究如何查詢一個內容提供器,如何修改內容提供器控制的資料,以及如何建立你自己的內容提供器。
內容提供器的基礎知識Content Provider Basics
內容提供器究竟如何在表層下儲存它的資料依賴於它的設計者。但是所有的內容提供器實現了一個公用的介面來查詢這個提供器和返回結果-增加,替換,和刪除資料也是一樣。
這是一個用戶端直接使用的介面,一般是通過ContentResolver對象。你可以通過getContentResolver()從一個活動或其它應用程式組件的實現裡擷取一個ContentResolver:
java代碼:
- ContentResolver cr = getContentResolver();
複製代碼
然後你可以使用這個ContentResolver的方法來和你感興趣的任何內容提供器互動。
當初始化一個查詢時,Android系統識別查詢目標的內容提供器並確保它正在運行。系統執行個體化所有的ContentProvider對象;你從來不需要自己做。事實上,你從來不會直接處理ContentProvider對象。通常,對於每個類型的ContentProvider只有一個簡單的執行個體。但它能夠和不同應用程式和進程中的多個ContentProvider對象通訊。進程間的互動通過ContentResolver和ContentProvider類處理。
資料模型The data model
內容提供器以資料庫模型上的一個簡單表格形式暴露它們的資料,這裡每一個行是一個記錄,每一列是特別類型和含義的資料。比如,關於個人資訊以及他們的電話號碼可能會以下面的方式展示:
13 |
(425) 555 6677 |
425 555 6677 |
Kirkland office |
Bully Pulpit |
TYPE_WORK |
44 |
(212) 555-1234 |
212 555 1234 |
NY apartment |
Alan Vain |
TYPE_HOME |
45 |
(212) 555-6657 |
212 555 6657 |
Downtown office |
Alan Vain |
TYPE_MOBILE |
53 |
201.555.4433 |
201 555 4433 |
Love Nest |
Rex Cars |
TYPE_HOME |
每個記錄包含一個數位_ID欄位用來唯一標識這個表格裡的記錄。IDs可以用來匹配相關表格中的記錄-比如,用來在一張表格中尋找個人電話號碼並在另外一張表格中尋找這個人的照片。
一個查詢返回一個Cursor 對象可在表格和列中移動來讀取每個欄位的內容。它有特定的方法來讀取每個資料類型。所以,為了讀取一個欄位,你必須瞭解這個欄位包含了什麼資料類型。(後面會更多的討論查詢結果和遊標Cursor對象)。
唯一資源標識符URIs
每個內容提供器暴露一個公開的URI(以一個Uri 對象封裝)來唯一的標識它的資料集。一個控制多個資料集(多個表)的內容提供器為每一個資料集暴露一個單獨的URI。所有提供器的URIs以字串"content://"開始。這個content:形式表明了這個資料正被一個內容提供器控制著。
如果你正準備定義一個內容提供器,為了簡化用戶端代碼和使將來的升級更清楚,最好也為它的URI定義一個常量。Android為這個平台所有的提供器定義了CONTENT_URI 常量。比如,匹配個人電話號碼的表的URI和包含個人照片的表的URI是:(均由連絡人Contacts內容提供器控制)
android.provider.Contacts.Photos.CONTENT_URI
類似的,最近撥打電話的表和議程表條目的URI如下:Similarly, the URIs for the table of recent phone calls and the table of calendar entries are:
android.provider.CallLog.Calls.CONTENT_URI
android.provider.Calendar.CONTENT_URI
這個URI常量被使用在和這個內容提供器所有的互動中。每個ContentResolver 方法採用這個URI作為它的第一個參數。正是它標識了ContentResolver應該和哪個內容提供器對話以及這個內容提供器的哪張表格是其目標。
查詢一個內容提供器Querying a Content Provider
你需要三方面的資訊來查詢一個內容提供器:
用來標識內容提供器的URI
你想擷取的資料欄位的名字
這些欄位的資料類型
如果你想查詢某一條記錄,你同樣需要那條記錄的ID。
產生查詢Making the query
你可以使用ContentResolver.query()方法或者Activity.managedQuery()方法來查詢一個內容提供器。兩種方法使用相同的參數序列,而且都返回一個Cursor對象。不過,managedQuery()使得活動需要管理這個遊標的生命週期。一個被管理的遊標處理所有的細節,比如當活動暫停時卸載自身,而活動重新啟動時重新查詢它自己。你可以讓一個活動開始管理一個尚未被管理的遊標對象,通過如下調用: Activity.startManagingCursor()。
無論query()還是managedQuery(),它們的第一個參數都是內容提供器的URI-CONTENT_URI常量用來標識某個特定的ContentProvider和資料集(參見前面的URIs)。
為了限制只對一個記錄進行查詢,你可以在URI後面擴充這個記錄的_ID值-也就是,在URI路徑部分的最後加上匹配這個ID的字串。比如,如果ID是23,那麼URI會是:
有一些輔助方法,特別是ContentUris.withAppendedId() 和Uri.withAppendedPath(),使得為URI擴充一個ID變得簡單。所以,比如,如果你想在連絡人資料庫中尋找記錄23,你可能需要構造如下的查詢語句:
java代碼:
- import android.provider.Contacts.People;
- import android.content.ContentUris;
- import android.net.Uri;
- import android.database.Cursor;
- // Use the ContentUris method to produce the base URI for the contact with _ID == 23.
- Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
- // Alternatively, use the Uri method to produce the base URI.
- // It takes a string rather than an integer.
- Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
- // Then query for this specific record:
- Cursor cur = managedQuery(myPerson, null, null, null, null);
複製代碼
query() 和managedQuery()方法的其它參數限定了更多的查詢細節。如下:
應該返回的資料列的名字。null值返回所有列。否則只有列出名字的列被返回。所有這個平台的內容提供器為它們的列定義了常量。比如,android.provider.Contacts.Phones類對前面說明過的通訊錄中各個列的名字定義了常量ID, NUMBER, NUMBER_KEY, NAME, 等等。
指明返回行的過濾器,以一個SQL WHERE語句格式化。 null值返回所有行。(除非這個URI限定只查詢一個單獨的記錄)。
選擇參數
返回行的排列順序,以一個SQL ORDER BY語句格式化(不包含ORDER BY本身)。null值表示以該表格的預設順序返回,有可能是無序的。
讓我們看一個查詢的例子吧,這個查詢擷取一個連絡人名字和首選電話號碼列表:
java代碼:
- import android.provider.Contacts.People;
- import android.database.Cursor;
- // Form an array specifying which columns to return.
- String[] projection = new String[] {
- People._ID,
- People._COUNT,
- People.NAME,
- People.NUMBER
- };
- // Get the base URI for the People table in the Contacts content provider.
- Uri contacts = People.CONTENT_URI;
- // Make the query.
- Cursor managedCursor = managedQuery(contacts,
- projection, // Which columns to return
- null, // Which rows to return (all rows)
- null, // Selection arguments (none)
- // Put the results in ascending order by name
- People.NAME + " ASC");
複製代碼
這個查詢從連絡人內容提供器中擷取了資料。它得到名字,首選電話號碼,以及每個連絡人的唯一記錄ID。同時它在每個記錄的_COUNT欄位告知返回的記錄數目。
列名的常量被定義在不同的介面中-_ID和_COUNT 定義在BaseColumns裡, NAME在PeopleColumns裡,NUMBER在PhoneColumns裡。Contacts.People類已經實現了這些介面,這就是為什麼上面的代碼執行個體只需要使用類名就可以引用它們的原因。
查詢的返回結果What a query returns
一個查詢返回零個或更多資料庫記錄的集合。列名,預設順序,以及它們的資料類型是特定於每個內容提供器的。但所有提供器都有一個_ID列,包含了每個記錄的唯一ID。另外所有的提供器都可以通過返回_COUNT 列告知記錄數目。它的數值對於所有的行而言都是一樣的。
下面是前述查詢的返回結果的一個例子:
44 |
3 |
Alan Vain |
212 555 1234 |
13 |
3 |
Bully Pulpit |
425 555 6677 |
53 |
3 |
Rex Cars |
201 555 4433 |
擷取到的資料通過一個遊標Cursor對象暴露出來,通過遊標你可以在結果集中前後瀏覽。你只能用這個對象來讀取資料。如果想增加,修改和刪除資料,你必須使用一個ContentResolver對象。