標籤:

談談ContentProvider?

ContentProvider是Android四大組件之一。一般在項目中都很少用到ContentProvider,但如果你在項目中負責底層數據的封裝,還是很有必要學習ContentProvider。

一、ContentProvider的角色

ContentProvider為存儲和獲取數據提供統一的介面,可以在不同應用程序之間共享數據。

ContentProvider主要有以下優點:

1.ContentProvider提供了對底層數據存儲方式的抽象。如底層可以採用SQLite方式存儲數據,使用ContentProvider封裝之後,即便底層換成XML存儲也不會對上層應用代碼產生影響。

2.Android框架中的一些類需要ContentProvider類型數據。如想讓數據可以使用在SyncAdapter,Loader,CursorAdapter等類上,那麼就需要為數據做一層ContentProvider封裝。

3.ContentProvider為應用間的數據交互提供了一個安全的環境。它准許你把自己的應用數據根據需求開放給其它應用進行增、刪、改、查,而不用擔心直接開放資料庫許可權而帶來的安全問題。

ContentProvider提供的方法有:

query:查詢ninsert:插入nupdate:更新ndelete:刪除ngetType:得到數據類型nonCreate:創建數據時調用的回調函數n

但如何上層對ContentProvider進行增、刪、改、查操作呢?答案是使用ContentResolver。

二、使用ContentResolver操作ContentProvider中的數據

為什麼要用ContentResolver來操作Provider,而不是直接使用訪問Provider呢?考慮到一個手機中很多應用含有Provider,如聯繫人,圖庫等。每個Provider具體實現都不一樣,如果開發時要了解每個ContentProvider,這可是非常不可取的方式啊。因此Android提供了ContentResolver來統一管理與不同ContentProvider間的操作。可以使用context.getContentResolver()來獲得ContentProvider。

但是ContentResolver又是如何操作ContentProvider的呢?

URI:統一資源標識。

每一個ContentProvider都擁有一個公共的URI,這個URI用於表示這個ContentProvider所提供的數據。

URI的格式為:

content:// 是標準前綴nAuthority:表示授權信息,是URI的標識,用於唯一標識這個ContentProvider,外部調用者可以根據這個標識來找到它。nPath:路徑名,即資料庫中的表名,用以區分ContentProvider中不同的數據表;nId:Id號,用以區別表中的不同數據;n

UriMatcher類使用

因為Uri代表了要操作的數據,所以我們經常需要解析Uri並從Uri中獲取數據。Android系統提供了兩個用於操作Uri的工具類,分別是UriMatcher和ContentUris。

使用UriMatcher時,首先註冊需要匹配的Uri路徑;然後,mMatcher.match(uri)方法對輸入的Uri進行匹配,如果匹配就返回匹配碼,匹配碼是addURI()方法中傳入的第三個參數。代碼如下:

UriMatcher mMatcher = new UriMatcher(UriMatcher.NO_MATCH);n//如果match()方法匹配content://com.example.procvide.personprovider/person路徑,返回匹配碼為1nmMatcher.addURI("com.example.procvide.personprovider", "person", 1);//添加需要匹配uri,如果匹配就會返回匹配碼n//如果match()方法匹配content://com.bing.provider.personprovider/person/100路徑,返回匹配碼為2nmMatcher.addURI("com.example.provider.personprovider", "person/#", 2);//#號為通配符nswitch (mMatcher.match(Uri.parse("content://com.example.provider.personprovider/person/10"))) { n case 1n break;n case 2n break;n default://不匹配n break;n}n

5、ContentUris類使用介紹

ContentUris類用於操作Uri路徑後面的ID部分,它有兩個比較實用的方法:withAppendedId(uri, id)用於為路徑加上ID部分;parseId(uri)方法用於從路徑中獲取ID部分。具體不做演示。

三、ContentProvider共享數據

ContentProvider共享數據是面試中經常被問題的一個問題。如:ContentProvider是如何實現共享數據的?ContentProvider如何控制數據訪問許可權?

1.ContentProvider是如何實現共享數據的?

當應用需要通過ContentProvider對外共享數據時,

第一步,繼承ContentProvider並重寫insert,query,...等重要方法:

第二步,在AndroidManifest.xml使用<provider>對該ContentProvider進行配置,為了能讓其他應用找到該ContentProvider,ContentProvider需要採用了authorities(主機名/域名)對它進行唯一標識:

<manifest .... > n <application android:icon="@drawable/icon" android:label="@string/app_name"> n <provider android:name=".PersonContentProvider" n android:authorities="com.example.providers.personprovider" /> n </application> n</manifest> n

然後,將數據添加到ContentProvider中。

第三步,在其它應用中通過ContentResolver使用定義的Uri訪問並操作這些被暴露的數據。

2.ContentProvider如何控制數據訪問許可權?

一種方法是向此應用設置一個android:sharedUserId,然後需要訪問此數據的應用也設置同一個sharedUserId,具有相同的sharedUserId的應用間可以共享數據。但是這種方法不夠安全,也無法做到對不同數據進行不同讀寫許可權的管理。

另一種方法是使用ContentProvider中的數據共享規則。這裡涉及到幾個重要的標籤:

android:exported 設置此provider是否可以被其他應用使用。nandroid:readPermission 該provider的讀許可權的標識nandroid:writePermission 該provider的寫許可權標識nandroid:permission provider讀寫許可權標識nandroid:grantUriPermissions 臨時許可權標識,true時,意味著該provider下所有數據均可被臨時使用;false時,則反之,但可以通過設置<grant-uri-permission>標籤來指定哪些路徑可以被臨時使用。如在啟動第三方應用時,傳入FLAG_GRANT_READ_URI_PERMISSION或FLAG_GRANT_WRITE_URI_PERMISSION來讓第三方應用臨時具有讀寫該數據的許可權。n

具體操作如下:

先修改AndroidManifest.xml,讓ContentProvider可以被其它應用查詢到:

<permission android:name="com.example.providers.personprovider.READ" android:protectionLevel="normal"/>n<providern android:authorities="com.example.providers.personprovider"n android:name=".PersonContentProvider"n android:readPermission="com.example.providers.personprovider.READ"n android:exported="true">n</provider>n

然後在其他應用中可以使用以下許可權來對PersonContentProvider進行訪問。

<uses-permission android:name="com.example.providers.personprovider.READ"/>n

如果希望對provider里不同的表面設置不同的許可權,需要使用provider提供的子標籤<path-permission>,可以對不同path設置不同的許可權規則

path-permission包括了以下幾個標籤。

<path-permission android:path=""n android:pathPrefix=""n android:pathPattern=""n android:permission=""n android:readPermission=""n android:writePermission="" />n

這樣就可以實現對ContentProvider中的數據訪問許可權進行控制了。

四、監聽者ContentObserver

如果ContentProvider的訪問者需要知道ContentProvider中的數據發生變化,可以在ContentProvider發生數據變化時調用getContentResolver().notifyChange(uri, null)來通知註冊在此URI上的訪問者,例子如下:

public class PersonContentProvider extends ContentProvider {n public Uri insert(Uri uri, ContentValues values) {n db.insert("person", "personid", values);n getContext().getContentResolver().notifyChange(uri, null);n }n}n

如果ContentProvider的訪問者需要得到數據變化通知,必須使用ContentObserver對數據(數據採用uri描述)進行監聽,當監聽到數據變化通知時,系統就會調用ContentObserver的onChange()方法:

getContentResolver().registerContentObserver(Uri.parse("content://com.example.providers.personprovider/person"),n true, new PersonObserver(new Handler()));npublic class PersonObserver extends ContentObserver{n public PersonObserver(Handler handler) {n super(handler);n }n public void onChange(boolean selfChange) {n //TODOn }n}n

推薦閱讀:

[譯] 如何創建高度模塊化的 Android 應用
Android 的 APK 中怎麼放置反編譯「炸彈」?
Android學習筆記——AS中使用AIDL
Android 開發助手 1.2.0 版

TAG:Android |