ContentProvider是在應(yīng)用程序間共享數(shù)據(jù)的一種接口機(jī)制,它使其他的應(yīng)用程序保存或讀取此ContentProvider的各種數(shù)據(jù)類型。
ContentProvider提供了更為高級(jí)的數(shù)據(jù)共享方法,應(yīng)用程序可以指定需要共享的數(shù)據(jù),而其他應(yīng)用程序則可以在不知數(shù)據(jù)來(lái)源、路徑的情況下,提供了查詢、添加、刪除和更新共享數(shù)據(jù)等操作的接口。許多Android系統(tǒng)的內(nèi)置數(shù)據(jù)也通過(guò)ContentProvider提供給用戶使用,如通訊錄、音視頻文件和圖像文件等。
ContentProvider的數(shù)據(jù)模式類似于數(shù)據(jù)庫(kù)的數(shù)據(jù)表,每行是一條記錄,每列具有相同的數(shù)據(jù)類型。每條記錄都包含一個(gè)long型的字段_ID,用來(lái)唯一標(biāo)識(shí)每條記錄。ContentProvider可以提供多個(gè)數(shù)據(jù)集,調(diào)用者使用URI對(duì)不同的數(shù)據(jù)集的數(shù)據(jù)進(jìn)行操作。
ContentProvider數(shù)據(jù)模型如表7-10所示。
表7-10 ContentProvider數(shù)據(jù)模型
_ID |
NAME |
AGE |
HEIGHT |
1 |
Tom |
21 |
1.81 |
2 |
Jim |
22 |
1.78 |
ContentProvider完全屏蔽了數(shù)據(jù)提供組件的數(shù)據(jù)存儲(chǔ)方法。在使用者看來(lái),數(shù)據(jù)提供者通過(guò)ContentProvider提供了一組標(biāo)準(zhǔn)的數(shù)據(jù)操作接口,卻無(wú)法得知數(shù)據(jù)提供者的數(shù)據(jù)存儲(chǔ)方法。數(shù)據(jù)提供者可以使用SQLite數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù),也可以通過(guò)文件系統(tǒng)或SharedPreferences存儲(chǔ)數(shù)據(jù),甚至是使用網(wǎng)絡(luò)存儲(chǔ)的方法,這些內(nèi)容對(duì)數(shù)據(jù)使用者都是不可見的。同時(shí)也正是因?yàn)槠帘螖?shù)據(jù)的存儲(chǔ)方法,很大程度上簡(jiǎn)化了ContentProvider的使用難度,使用者只要調(diào)用ContentProvider提供的接口方法,就可完成所有的數(shù)據(jù)操作。
圖7-9顯示了ContentProvider的調(diào)用關(guān)系。

圖7-9 ContentProvider的調(diào)用關(guān)系圖
首先,在創(chuàng)建ContentProvider時(shí),需要先實(shí)現(xiàn)底層的存儲(chǔ)功能,可以是數(shù)據(jù)庫(kù)、文件系統(tǒng)或是網(wǎng)絡(luò)存儲(chǔ)等,然后在繼承ContentProvider的類中實(shí)現(xiàn)基本數(shù)據(jù)操作的接口方法,包括添加、刪除、查找和更新等功能。接口主要有以下幾個(gè)。
□ query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder):通過(guò)Uri 進(jìn)行查詢,返回一個(gè)Cursor。
□ insert(Uri url, ContentValues values):將一組數(shù)據(jù)插入U(xiǎn)ri 指定的地方。
□ update(Uri uri, ContentValues values, String where, String[] selectionArgs):更新Uri 指定位置的數(shù)據(jù)。
□ delete(Uri url, String where, String[] selectionArgs):刪除指定Uri 并且符合一定條件的數(shù)據(jù)。
其次,我們看出調(diào)用者不能夠直接調(diào)用ContentProvider的接口方法,而需要使用ContentResolver對(duì)象,通過(guò)Uri間接調(diào)用ContentProvider。那么什么是ContentResolver對(duì)象呢?
ContentResolver 接口是外界的程序訪問ContentProvider 提供的數(shù)據(jù)橋梁, ContentResolver 提供的接口和ContentProvider 中需要實(shí)現(xiàn)的接口對(duì)應(yīng),主要有以下幾個(gè)。
□ query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder):通過(guò)Uri 進(jìn)行查詢,返回一個(gè)Cursor。
□ insert(Uri url, ContentValues values):將一組數(shù)據(jù)插入U(xiǎn)ri 指定的地方。
□ update(Uri uri, ContentValues values, String where, String[] selectionArgs):更新Uri 指定位置的數(shù)據(jù)。
□ delete(Uri url, String where, String[] selectionArgs):刪除指定Uri 并且符合一定條件的數(shù)據(jù)。
程序開發(fā)人員在Activity 當(dāng)中通過(guò)getContentResolver()可以得到當(dāng)前應(yīng)用的ContentResolver 對(duì)象,然后使用該ContentResolver對(duì)象與ContentProvider進(jìn)行交互,而ContentResolver則通過(guò)Uri確定需要訪問的ContentProvider的數(shù)據(jù)集。在發(fā)起一個(gè)請(qǐng)求的過(guò)程中,Android首先根據(jù)Uri確定處理這個(gè)查詢的ContentResolver,然后初始化ContentResolver所有需要的資源,這個(gè)初始化的工作無(wú)須程序開發(fā)人員參與,是Android系統(tǒng)完成的。一般情況下只有一個(gè)ContentProvider對(duì)象,但卻可以同時(shí)與多個(gè)ContentResolver在不同的應(yīng)用程序和不同的進(jìn)程中進(jìn)行交互。
Uri是通用資源標(biāo)志符(Uniform Resource Identifier),用來(lái)定位任何遠(yuǎn)程或本地的可用資源。在ContentProvider 和ContentResolver 當(dāng)中用到的Uri語(yǔ)法結(jié)構(gòu)如代碼清單7-46所示。
代碼清單7-46 ContentProvider使用的Uri語(yǔ)法結(jié)構(gòu)
content://<authority>/<data_path>/<id>
content://是通用前綴,表示該Uri用于ContentProvider定位資源,無(wú)須修改;<authority>是授權(quán)者名稱,用來(lái)確定具體由哪一個(gè)ContentProvider提供資源。因此,一般<authority>都由類的包名+類名小寫全稱組成,以保證唯一性。
<data_path>是數(shù)據(jù)路徑,用來(lái)確定請(qǐng)求的是哪個(gè)數(shù)據(jù)集。如果ContentProvider僅提供一個(gè)數(shù)據(jù)集,數(shù)據(jù)路徑則是可以省略的;如果ContentProvider提供多個(gè)數(shù)據(jù)集,數(shù)據(jù)路徑則必須指明具體是哪一個(gè)數(shù)據(jù)集。數(shù)據(jù)集的數(shù)據(jù)路徑可以寫成多段格式,例如/people/girl和/people/boy。
Uri 可以指定全部數(shù)據(jù),也可以是指定某個(gè)ID 的數(shù)據(jù)。這里我們就用到了上述語(yǔ)法結(jié)構(gòu)中的后一個(gè)參數(shù):<id>。<id>>是數(shù)據(jù)編號(hào),用來(lái)唯一確定數(shù)據(jù)集中的一條記錄,用來(lái)匹配數(shù)據(jù)集中_ID字段的值,如果沒有指定<id>,那么表示返回全部。請(qǐng)求整個(gè)people數(shù)據(jù)集的Uri應(yīng)寫為如代碼清單7-47所示的代碼。
代碼清單7-47 請(qǐng)求數(shù)據(jù)的Uri例子
//請(qǐng)求全部的聯(lián)系人數(shù)據(jù)的Uri
content://contacts/people/
//請(qǐng)求ID 為1 的聯(lián)系人的數(shù)據(jù)的Uri
content://contacts/people/1
//請(qǐng)求整個(gè)people數(shù)據(jù)集的Uri
content://cn.com.farsight.peopleprovider/people
//請(qǐng)求people數(shù)據(jù)集中第3條數(shù)據(jù)的Uri
content://cn.com.farsight.peopleprovider/people/3