7.3.1 ContentResolver的基本用法
通過借助ContentResolver類訪問內(nèi)容提供器中共享的數(shù)據(jù),可以通過Context中的getContentResolver()方法獲取該類實(shí)例。
ContentResolver中的增刪改查方法都不接收表名參數(shù),而是使用一個Uri參數(shù)代替,這個參數(shù)被稱為內(nèi)容URI。內(nèi)容URI給內(nèi)容提供器中的數(shù)據(jù)建立了唯一一個標(biāo)識符,主要由兩部分組成:authority和path。authority是用于對不同的應(yīng)用程序作區(qū)分的,采用程序包和路徑的命名方式進(jìn)行命名。比如某個程序包的名是
com.example.app
那么該程序?qū)?yīng)的authority就可以命名為
com.example.app.provider
path則是用于對同一應(yīng)用程序中不同的表作區(qū)分的,通常都會添加到authority的后面。比如某個程序的數(shù)據(jù)庫里存在兩張表:table1和table2,這是就可以將path分別命名為/table1和/table2,然后把a(bǔ)uthority和path進(jìn)行組合,內(nèi)容URI就變成了
com.example.app.provider/table1
和
com.example.app.provider/table2
不過,還很難辨認(rèn)出這兩個字符串就是兩個內(nèi)容URI,我們還需要在字符串的頭部加上協(xié)議聲明。因此,內(nèi)容URI最標(biāo)準(zhǔn)的格式寫法如下:
content://com.example.app.provider/table1
content://com.example.app.provider/table2
之后我們還需要將它解析成Uri對象才可以作為參數(shù)傳入:
Uri uri = Uri.parse("content://com.example.app.provider/table1")
現(xiàn)在可以使用這個Uri對象來查詢table1表中的數(shù)據(jù)了:
Cursor cursor = getContentResolver().query(
uri,
projection,
selection,
selectionArgs,
sortOrder);
查詢完成后仍返回一個Cursor對象,這是我們就可以將數(shù)據(jù)從Cursor對象中逐個讀取出來了。讀取的思路仍然是通過移動游標(biāo)的位置來遍歷Cursor的所有航,然后再取出每一行中相應(yīng)列的數(shù)據(jù),代碼如下:
if (cursor != null) {
while (cursor.moveToNext()) {
String column1 = cursor.getString(cursor.getColumnIndex("column1"));
int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
}
cursor.close();
}
7.4 創(chuàng)建內(nèi)容提供器的步驟
如果想要實(shí)現(xiàn)跨程序貢獻(xiàn)數(shù)據(jù)的功能,官方推薦的方式就是使用內(nèi)容提供器,可以通過新建一個類去繼承ContentProvider的方式來創(chuàng)建一個自己的內(nèi)容提供器。ContentProvider類中有6個抽象方法,我們在使用子類繼承它的時候,需要將6個方法全部重寫。
每一個方法都會帶有Uri這個參數(shù),這個參數(shù)也正是調(diào)用ContentResolver的增刪改查方法時傳遞過來的,我們需要對傳入的Uri參數(shù)進(jìn)行解析,從中分析出調(diào)用方期望訪問的表和數(shù)據(jù),一個標(biāo)準(zhǔn)內(nèi)容的URI寫法是這樣的:
content://com.example.app.provider/table1
這樣表示調(diào)用方期望訪問的是com.example.app這個應(yīng)用的tale1表中的數(shù)據(jù)。除此之外,我們還可以在這個內(nèi)容URI的后面加上一個id,如下所示:
content://com.example.app.provider/table1/1
這就表示調(diào)用方期望訪問得失com.example.app這個應(yīng)用的table1表中的id為1的數(shù)據(jù)。我們可以使用通配符的方式來分別匹配這兩種格式的內(nèi)用URI,規(guī)則如下:
- *:表示匹配任意長度的任意字符。
- #:表示匹配任意長度的數(shù)字。
所以,一個能夠匹配任意表的內(nèi)容URI格式就可以寫成:
content://com.example.app.provider/*
而一個能夠匹配table1表中任意一行數(shù)據(jù)的內(nèi)容URI格式就可以寫成:
content://com.example.app.provider/table1/#
接著,我們在借助UriMatcher這個類就可以輕松地實(shí)現(xiàn)匹配內(nèi)容URI的功能。UriMatcher中提供了一個addURI()方法,這個方法接收3個參數(shù),可以分別吧authority、path和一個自定義代碼轉(zhuǎn)進(jìn)去。這樣,當(dāng)調(diào)用UriMatcher的match()方法時,就可以將一個Uri對象傳入,返回值是某個能夠匹配這個Uri對象所對應(yīng)的自定義代碼,利用這個代碼,我們可以判斷出調(diào)用方期望訪問的事那張表中的數(shù)據(jù)了。
getType()方法是所有內(nèi)容提供器都必須提供的一個方法,用于獲取Uri對象所對應(yīng)的MIME類型。一個融融URI多對應(yīng)的MIME字符串主要由3個部分組成,Android對這3個部分做了如下格式規(guī)定。
- 必須以vnd開頭。
- 如果內(nèi)容URI以路徑結(jié)尾,則后接
android.cursor.dir/,如果內(nèi)容URI以id結(jié)尾,則后接android.cursor.item/。 - 最后接上
vnd.<authority>.<path>。
所以,對于content://com.example.app.provider/table1這個內(nèi)容URI,它所對應(yīng)的MIME類型就可以寫成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1
對于content://com.example.app.provider.table1/1這個內(nèi)容URI,它所對應(yīng)的MIME類型就可以寫成:
vnd.android.cursor.item/vnd.com.example.app.provider.table1