Content Provider的架構
Authority類似web中的網域名稱,每個content provider會通過AndroidManifest.xml向系統註冊authority,如下。其中name是類名,即如何找尋這個content
provider。可以省去AndroidManifest.xml中package name,不需要寫完整的類名。如android:name=".BookProvider"。
<provider android:name="SomeProvider" android:authorities="com.your-company.SomeProvider" />
<provider android:name="NotePadProvider" android:authorities="com.google.provider.NotePad" />
和web的URL網域名稱類似,content provider進行資料訪問的URL為content://authority/......,例如content://com.your-company.SomeProvider/。對於Android自己提供的content provider,有時會寫的比較簡單,例如用contacts來代替com.google.android.contacts,如content://contacts/……。
有時註冊的provider會比較複雜,例如Android的連絡人資訊,其uri為content://com.android.contacts/contacts,其原始碼資訊為如下,該provider需要讀寫權限。
<provider android:name="ContactsProvider2"
android:authorities="contacts;com.android.contacts"
android:label="@string/provider_label"
android:multiprocess="false"
android:readPermission="android.permission.READ_CONTACTS"
android:writePermission="android.permission.WRITE_CONTACTS">
<path-permission
android:pathPrefix="/search_suggest_query"
android:readPermission="android.permission.GLOBAL_SEARCH"/>
<path-permission
android:pathPrefix="/search_suggest_shortcut"
android:readPermission="android.permission.GLOBAL_SEARCH"/>
<path-permission
android:pathPattern="/contacts/.*/photo"
android:readPermission="android.permission.GLOBAL_SEARCH"/>
<grant-uri-permission android:pathPattern=".*" />
</provider>
Content URI的結構。Android通過Content URI來擷取資料,並返回具有行列結構的遊標cursor。content UI的格式為:
content://<authority-name>/<path-segment1>/<path-segment2>/etc…
例子:content://com.google.provider.NotePad/notes/23
例子的/notes表示collection,或理解為一個目錄,稱為path segment,而/23表示特定的item,是具體的index,content provider提供的是二維資料,這就是該row的_id值。
MIME Type。HTTP響應會帶有MIME Type,最長江就是text/html,告知body的資料類型。Content Provider也一樣,可以用方法獲得MIME。MIME由兩部分組成:type/subtype,具體可以參考rfc2046。type和subtype的定義可以在IANA中查到。下面是MIME的幾個例子:
text/xml
application/rtf
application/vnd.ms-excel //vnd是vendeor-specific,廠家自訂格式,如此處的微軟excel格式
application/x-tar //x-表示自訂的私人格式
在Content Provider中可以存在多層目錄,即存在item和collection,相應地分別有item的MIME tye和collection的MIME type。Android採用namespace的方式定義type和subtype。如下:
vnd.android.cursor.item/vnd.<yourcompanyname.contenttype> 是item的MIME type
vnd.android.cursor.dir/vnd.<yourcompanyname.contenttype>是collection的MIME type
從上面的格式可以看到,type已指定,開發人員只能對subtype進行設定。
定義清晰描述。我們應該為所建立的content provider提供清晰的定義或描述,可通過所使用的Uri進行constant的預定義。例如MediaStore.Images.Media.INTERNETAL_CONTENT_URI表示content://media/internal/images。同時我們也應為個列
小例子:讀取連絡人資訊。Provider通過uri去訪問,返回遊標(cursor),我們將通過下面的小例子進行驗證,先進行Uri的瞭解,然後對cursor進行二次輪詢,一次採用while,一次採用for方式。正如前面的contact provider在xml的定義所示,有讀寫權限限制,因此在XML中應賦予相應的許可權:<uses-permission
android:name="android.permission.READ_CONTACTS" />
private void contentProviderTest(){ /* Contact的內容很多,我們只選取部分列名字,相當於SELECT xxxx FROM ....中的xxxx。如果是自己建立建立的Content Provider,也應當採用constant的方式了明晰表示每項的內容*/
String[] contactProjection = new String[]{ Contacts._ID, /* 每一行都有一個唯一的_id來表示 */
Contacts.DISPLAY_NAME_PRIMARY }; /* 下面是一些uri的操作,作為測試,通過provider的Uri都會提供constant的方式 */
Uri peopleBaseUri = ContactsContract.Contacts.CONTENT_URI; showInfo(peopleBaseUri.toString()); //showInfo( )資訊顯示,我將在TextView中呈現內容 Uri myPersonUri = Uri.withAppendedPath(peopleBaseUri, "1"); showInfo(myPersonUri.toString()); /* managedQuery( )從Content Provider讀取資料,返回Cursor
* 第1參數:Uri uri表示URI; * 第2參數:String[] projection表示所需讀取的資訊; * 第3參數:String selection數是限制條件,類似SQL中的WHERE,但去掉了“WHERE”; * 第4參數:String[] selectionArgs和第3個參數配合使用,具體描述第三個參數中的“?”為何; * 第5參數:String sortOrder,類似於SQL中的ORDER BY */ @SuppressWarnings("deprecation") //在API Level 11,也就是Android3.0後由CursorLoader替代,為了不使Eclipse警示告,我們先在此禁止警告。看到Eclipse有個小三角的警示說明,覺得不舒服,幹掉它。^_^
Cursor cur = managedQuery(ContactsContract.Contacts.CONTENT_URI,
contactProjection, null, null, null); showInfo("query Contacts get cursor : " + cur);
showInfo("cursor has " + cur.getCount() + " rows.");
// 輪詢方式一: 通過while showInfo("read from cursor"); //遊標是rows的集合,首先需要使用moveToFirst(),因為query後遊標是位於第一行的前面。返回false,表示為空白。
if(!cur.moveToFirst()){ showInfo("no rows. It's empty"); cur.close(); return; } //遊標可以前後移動,去可以查看不同行的資料,還可以指定特定的行,它的移動非常靈活。遊標對資料的擷取是基於column number,可通過列名來擷取。
int nameColumnIndex = cur.getColumnIndex(Contacts.DISPLAY_NAME_PRIMARY);
showInfo("\t Name: " + cur.getString(nameColumnIndex));
while(cur.moveToNext()){ showInfo("\t Name: " + cur.getString(nameColumnIndex));
} //輪詢方式二:通過for showInfo("read from cursor again"); for(cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()){ String name = cur.getString(nameColumnIndex); showInfo("\t Name: " + name); } cur.close(); } |
Where條件的用法。尋找特定的資料,可以利用Uri,也可以利用manageQuery()方法的參數。例如希望查詢select * from notes where _id=23,利用Uri,可以設定為
String noteUri = “content://com.google.progider.NotePad/notes/23”;
利用manageQuery( )中的selection擦數,同樣可以表達為
managedQuery(uri, //為"content://com.google.provider.NotePad/notes"
null,
"_id=?" ,
new String[] {23} ,
null);
增加、修改、刪除資料。增刪改查是資料讀寫的四大功能,我們將在後面的小例子中給出詳細的說明。
相關連結:
我的Android開發相關文章