Android基礎 : Android ContentProvider和getContentResolver
最近頭有點大我們說點基礎吧,今天心情不錯.那就直入主題
ContentProvider
因為在Android系統裡面,資料庫是私有的。一般情況下外部應用程式是沒有許可權讀取其他應用程式的資料。如果你想公開你自己的資料,你有兩個選擇:你可以建立你自己的內容提供器(一個ContentProvider子類)或者你可以給已有的提供器新增資料-如果存在一個控制同樣型別資料的內容提供器且你擁有寫的許可權。而外界根本看不到,也不用看到這個應用暴露的資料在應用當中是如何儲存的,或者是用資料庫儲存還是用檔案儲存,還是通過網上獲得,這些一切都不重要,重要的是外界可以通過這一套標準及統一的介面和程式裡的資料打交道,可以讀取程式的資料,也可以刪除程式的資料,當然,中間也會涉及一些許可權的問題。

image.png
應用程式可以在Content Provider中執行如下操作:
查詢資料
修改資料
新增資料
刪除資料
當我們不需要把資料提供給第三方應用程式使用的話,可以不實現Content Provider。
ContentResolver / getContentResolver()
外界的程式通過ContentResolver介面可以訪問ContentProvider提供的資料,在Activity當中通過getContentResolver()可以得到當前應用的 ContentResolver例項。ContentResolver提供的介面和ContentProvider中需要實現的介面對應,具體可以檢視API Doc,不過可以發現ContentResolver裡面的方法很多都是final或者static的。
在實際應用中,我們很少實現ContentResolver抽象類,更多時候通過getContentResolver()從一個Activity或其它應用程式元件的實現裡獲取一個ContentResolver:

image.png
然後你可以使用這個ContentResolver的方法來和你感興趣的任何內容提供器互動。
當初始化一個查詢時,Android系統識別查詢目標的內容提供器並確保它正在執行。系統例項化所有的ContentProvider物件;你從來不需要自己做。事實上,你從來不會直接處理ContentProvider物件。通常,對於每個型別的ContentProvider只有一個簡單的例項。但它能夠和不同應用程式和程序中的多個ContentProvider物件通訊。程序間的互動通過ContentResolver和ContentProvider類處理。
如果有興趣的話可以加入Android工程師交流Q群:752016839 主要針對Android開發人員提升自己,突破瓶頸,相信你來會有提升和收穫。這裡會有你所需要的內容。
查詢記錄:
在Content Provider中使用的查詢字串有別於標準的SQL查詢。很多諸如select, add, delete, modify等操作我們都使用一種特殊的URI來進行,這種URI由3個部分組成, “content://”, 代表資料的路徑,和一個可選的標識資料的ID。以下是一些示例URI:
ofollow,noindex">content://media/internal/images 這個URI將返回裝置上儲存的所有圖片
content://contacts/people/ 這個URI將返回裝置上的所有聯絡人資訊
content://contacts/people/45 這個URI返回單個結果(聯絡人資訊中ID為45的聯絡人記錄)
儘管這種查詢字串格式很常見,但是它看起來還是有點令人迷惑。為此,Android提供一系列的幫助類(在android.provider包下),裡面包含了很多以類變數形式給出的查詢字串,這種方式更容易讓我們理解一點,參見下例:
MediaStore.Images.Media.INTERNAL_CONTENT_URI
Contacts.People.CONTENT_URI
因此,如上面 content://contacts/people/45 這個URI就可以寫成如下形式:
Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);
然後執行資料查詢:
Cursor cur = managedQuery(person, null, null, null);
這個查詢返回一個包含所有資料欄位的遊標,我們可以通過迭代這個遊標來獲取所有的資料:

image.png
上例示範了一個如何依次讀取聯絡人資訊表中的指定資料列name和number。
修改記錄:
我們可以使用ContentResolver.update()方法來修改資料,我們來寫一個修改資料的方法:

image.png
現在你可以呼叫上面的方法來更新指定記錄:
updateRecord(10, ”XYZ”); //更改第10條記錄的name欄位值為“XYZ”
新增記錄:
要增加記錄,我們可以呼叫ContentResolver.insert()方法,該方法接受一個要增加的記錄的目標URI,以及一個包含了新記錄值的Map物件,呼叫後的返回值是新記錄的URI,包含記錄號。
上面的例子中我們都是基於聯絡人資訊簿這個標準的Content Provider,現在我們繼續來建立一個insertRecord() 方法以對聯絡人資訊簿中進行資料的新增:
如果有興趣的話可以加入Android工程師交流Q群:752016839 主要針對Android開發人員提升自己,突破瓶頸,相信你來會有提升和收穫。這裡會有你所需要的內容。

image.png
這樣我們就可以呼叫insertRecords(name, phoneNo)的方式來向聯絡人資訊簿中新增聯絡人姓名和電話號碼。
刪除記錄:
Content Provider中的getContextResolver.delete()方法可以用來刪除記錄,下面的記錄用來刪除裝置上所有的聯絡人資訊:

image.png
你也可以指定WHERE條件語句來刪除特定的記錄:
getContentResolver().delete(uri, “NAME=” + “‘XYZ XYZ’”, null);
這將會刪除name為‘XYZ XYZ’的記錄。
建立Content Provider:
至此我們已經知道如何使用Content Provider了,現在讓我們來看下如何自己建立一個Content Provider。
要建立我們自己的Content Provider的話,我們需要遵循以下幾步:
- 建立一個繼承了ContentProvider父類的類
-
定義一個名為CONTENT_URI,並且是public static final的Uri型別的類變數,你必須為其指定一個唯一的字串值,最好的方案是以類的全名稱, 如:
public static final Uri CONTENT_URI = Uri.parse( “ content://com.google.android.MyContentProvider ”);
-
建立你的資料儲存系統。大多數Content Provider使用Android檔案系統或SQLite資料庫來保持資料,但是你也可以以任何你想要的方式來儲存。
-
定義你要返回給客戶端的資料列名。如果你正在使用Android資料庫,則資料列的使用方式就和你以往所熟悉的其他資料庫一樣。但是,你必須為其定義一個叫_id的列,它用來表示每條記錄的唯一性。
-
如果你要儲存位元組型資料,比如點陣圖檔案等,那儲存該資料的資料列其實是一個表示實際儲存檔案的URI字串,客戶端通過它來讀取對應的檔案資料,處理這種資料型別的Content Provider需要實現一個名為_data的欄位,_data欄位列出了該檔案在Android檔案系統上的精確路徑。這個欄位不僅是供客戶端使用,而且也可以供ContentResolver使用。客戶端可以呼叫ContentResolver.openOutputStream()方法來處理該URI指向的檔案資源,如果是ContentResolver本身的話,由於其持有的許可權比客戶端要高,所以它能直接訪問該資料檔案。
-
宣告public static String型的變數,用於指定要從遊標處返回的資料列。
-
查詢返回一個Cursor型別的物件。所有執行寫操作的方法如insert(), update() 以及delete()都將被監聽。我們可以通過使用ContentResover().notifyChange()方法來通知監聽器關於資料更新的資訊。
-
在AndroidMenifest.xml中使用<provider>標籤來設定Content Provider。
-
如果你要處理的資料型別是一種比較新的型別,你就必須先定義一個新的MIME型別,以供ContentProvider.geType(url)來返回。MIME型別有兩種形式:一種是為指定的單個記錄的,還有一種是為多條記錄的。這裡給出一種常用的格式:
vnd.android.cursor.item/vnd.yourcompanyname.contenttype (單個記錄的MIME型別)
比如, 一個請求列車資訊的URI如 content://com.example.transportationprovider/trains/122 可能就會返回typevnd.android.cursor.item/vnd.example.rail這樣一個MIME型別。
vnd.android.cursor.dir/vnd.yourcompanyname.contenttype (多個記錄的MIME型別)
-
比如, 一個請求所有列車資訊的URI如 content://com.example.transportationprovider/trains 可能就會返回vnd.android.cursor.dir/vnd.example.rail這樣一個MIME 型別。
下列程式碼將建立一個Content Provider,它僅僅是儲存使用者名稱稱並顯示所有的使用者名稱稱(使用 SQLLite資料庫儲存這些資料):

image.png
上面的類中定義了Content Provider的CONTENT_URI,以及資料列。下面我們將定義基於上面的類來定義實際的Content Provider類:
如果有興趣的話可以加入Android工程師交流Q群:752016839 主要針對Android開發人員提升自己,突破瓶頸,相信你來會有提升和收穫。這裡會有你所需要的內容。

image.png

image.png
一個名為MyContentProvider的Content Provider建立完成了,它用於從Sqlite資料庫中新增和讀取記錄。
Content Provider的入口需要在AndroidManifest.xml中配置:
<provider android:name=”MyContentProvider” android:authorities=”com.wissen.MyContentProvider” />
之後,讓我們來使用這個定義好的Content Provider:

image.png
上面的類將先向資料庫中新增一條使用者資料,然後顯示資料庫中所有的使用者資料。
至此,我們已經明白如何來使用和建立Content Provider了。