Pro Android學習筆記(一)——ContentProvider(上)
ContentProvider,Android四大元件之一。他是系統提供的一種抽象的資料服務。Android Developer對她的概述為:
大概意思就是說ContentProvider(內容提供者)就是為應用程式提供資料。他壓縮資料並通過ContentResolver介面提供給應用程式。當我們需要在多個應用程式之間共享資料的時候,我們才考慮使用ContentProvider,否則我們可以直接使用SQLiteDataBase。當一個URI形式的請求通過ContentResolver並且通過註冊的Authority請求ContentProvider的時候,ContentProvider可以把URI解釋成它想要的(這一段話我也不太會翻譯,有不對的地方還望斧正)。
我們看看這裡面涉及到了哪些概念:
(1)ContentProvider,內容提供者。
(2)ContentResolver,用於資料操作的抽象類。
(3)URI,代表了要操作的資料,類似於HTTP URI。
(4)UriMatcher,Uri匹配器,對傳遞過來的URI進行分析匹配。
以後,還會涉及到
(5)ContentValue,儲存鍵值對用於ContentResolver處理。
(6)Cursor,游標,可以想象成文字編輯器中的游標。
官方的概述還是很難理解,我們慢慢來看。
(一)檢視Android內建ContentProvider
使用adb可以檢視裝置內部的ContentProvider。將手機(此處手機應為root之後)連線電腦或者開啟模擬器,命令列開啟adb。
使用adb devices可以檢視所連線裝置
在這裡我使用的是Genymotion的模擬器,號稱最快的模擬器。
然後鍵入adb shell就可以進入android裝置的shell。
在這裡我們就能進行一些linux命令的操作,但是,但是,對linux的命令支援並不全面,很多都沒有。可以使用“ls /system/bin”命令檢視可以執行哪些命令。
太多就不截了。
OK,通過命令"ls -l /data/data/"我們能夠檢視/data/data/目錄下的檔案,這裡面就儲存了應用程式的資料檔案,包括資料庫。
來看下聯絡人示例,聯絡人儲存在"/data/data/com.android.providers.cantacts/"下,通過命令“ls /data/data/com.android.providers.contacts/”檢視該檔案下的資料
可以看到其中都儲存了些什麼,我們只關心database,所以執行“ls /data/data/com.android.providers.contacts/databases”
裡面以資料庫的格式儲存了我們的聯絡人。
我們可以使用sqlite3對資料庫進行操作,執行“sqlite3 /data/data/com.android.proviers.contacts/databases/contacts.db”
注意此處,由shell環境進入到了sqlite的操作環境。
執行".help"可以檢視可執行命令了,在此不多說了。我們通過命令列檢視資料庫總是不方便,我們可以匯出檔案到本地電腦,然後通過圖形化工具檢視。首先,回退到windows的cmd環境底下,執行命令“adb pull /data/data/com.android.providers/contacts/contacts.db D:/”,這裡我匯出到了我本地磁碟D盤。
然後就可以用資料庫工具查看了,Pro Android中使用的是Sqliteman。
記錄一些常用資料庫語言:
select * from table1;
select count(*) from table1;
select col1, col2 from table1;
select distinct col1 from table1;
select count(col1) from (select distinct col1 from table1);
select count(*), col1 from table1 group by col1;
select * from table1 t1, table2 t2 where t1.col1 = t2.col1;
select * from table t1 left outer join table2 t2 on t1.col1 = t2.col1 where ....
以上是我們檢視Android裝置中的ContentProvider,因為ContentProvider主要使用資料庫儲存,所以我們基本是檢視的資料庫。
(二)ContentProvider的架構
我們在程式中使用ContentProvider的時候,首先需要註冊,提供授權(Authority),vnd.android.cursor.dir/vnd.<yourcompanyname.contenttype>
在AndroidManifest檔案中進行註冊
<provider android:name="SomeProvider" android:authorities="com.your-company.SomeProvider" />
其中,name即自定義ContentProvider的類名,可以省略包名;authorities即是為我們提供可使用的URI。
註冊之後,我們就可以使用content://com.your-company.SomeProvider/來進行訪問了。
在Android中,對於系統級程式我們可以使用簡寫的URI來進行訪問,比如聯絡人可以直接使用contracts。然而對於我們自己的程式,則需要使用全稱,否則無法使用。
以下提供了系統的contacts的註冊
<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>
URI:上面提到的“content://com.your-company.SomeProvider/”就是一個URI,有沒有一種很眼熟的感覺,對,他就像HTTP一樣,因為ContentProvider才用了REST和Web服務的抽象機制。
uri的格式如下:
content://<authority-name>/<path-segment1>/<path-segment2>/etc…
例子:content://com.google.provider.NotePad/notes/23
其中,notes就是path-segment,而23,就是我們要訪問資源的ID。
MIME Type:我們進行了一次URI請求之後就會返回資料,這類資料的型別就用MIME來表示。Android遵循了一定的約定來定義MIME型別。
對於單條記錄:
vnd.android.cursor.item/vnd.<yourcompanyname.contenttype>
對於記錄或行的集合:
vnd.android.cursor.dir/vnd.<yourcompanyname.contenttype>
其中,vnd表示這些型別和子型別具有非標準的、供應商特定的形式。對於Android,本質上能識別項是“單個”還是“集合”項,作為程式設計師,我們只關心子型別,即
vnd.<yourcompanyname.contenttype>
Cursor:遊標是一個行集合,在讀取資料之前,我們需要使用moveToFirst(),將遊標放置第一行。使用遊標的時候,需要知道列型別和列名稱,在訪問之前,需要將列名稱轉化為列編號,通過遊標,可以獲取行計數。
以下示例演示瞭如何使用URI從ContentProvider獲取一個遊標
// An array specifying which columns to return
Sting[] projection = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME_PRIMARY
};
Uri mContactsUri = ContactsContract.Contacts.CONTENT_URI;
// Best way to retrieve a query; returns a managed query
Cursor managedCursor = managedQuery(mContactsUri,
projection, // which columns to return
null, // where clause
Contacts.DISPLAY_NAME_PRIMARY + " ASC"); // Order-by clause
Where條件語句的用法:ContentProvider提供了兩種方式來傳遞where字句
1、通過URI
Activity somActivity
// ..intialize someActivity
String moteUri = "content://com.google.provider.NotePad/notes/23";
Cursor managedCursor = someActivity.managedQuery(noteUri,
projection, // Which columns to return.
null, // WHERE clause
null); // Order-by clause
2、通過string字句與一組可替換的字串資料引數的組合
public final Cursor managedQuery(Uri uri,
String[] projection,
String selection,
String[] seleciontArgs,
String sortOrder)