轉載博客:http://blog.csdn.net/yhaolpz/article/details/51304345
參考博客:http://blog.sina.com.cn/s/blog_9f233c070101euqx.html
ContentProvider調用關係:
ContentProvider(數據提供者)是應用程序之間共享數據的一種接口機制,是一種更爲高級的數據共享方法。
- ContentProvider可以指定需要共享的數據,而其他應用程序則可以在不知道數據來源、路徑的情況下,對共享數據進行增刪改查等操作。
- 在Android系統中,許多Android系統內置的數據也是通過ContentProvider提供給用戶使用,例如通訊錄、音視頻文件和圖像文件等。
通用資源標識符(Uniform Resource Identifier)
URI是一個用於標識某一互聯網資源名稱的字符串。 該種標識允許用戶對任何(包括本地和互聯網)的資源通過特定的協議進行交互操作。在ContentProvider機制中,使用ContentResolver對象通過URI定位ContentProvider提供的資源。
ContentProvider使用的URI語法結構如下:
content://<authority>/<data_path>/<id>
- content:// 是通用前綴,表示該UIR用於ContentProvider定位資源。
- < authority > 是授權者名稱,用來確定具體由哪一個ContentProvider提供資源。因此一般< authority >都由類的小寫全稱組成,以保證唯一性。
- < data_path > 是數據路徑,用來確定請求的是哪個數據集。如果ContentProvider近提供一個數據集,數據路徑則可以省略;如果ContentProvider提供多個數據集,數據路徑必須指明具體數據集。數據集的數據路徑可以寫成多段格式,例如people/girl和people/boy。
- < id > 是數據編號,用來唯一確定數據集中的一條記錄,匹配數據集中_ID字段的值。如果請求的數據不只一條,< id >可以省略。
如請求整個people數據集的URI爲:
content://com.example.peopleprovider/people
而請求people數據集中第3條數據的URI則應寫爲:
content://com.example.peopleprovider/people/3
創建數據提供者
1. 創建一個類讓其繼承ContentProvider,並重載6個函數
-
onCreate()
一般用來初始化底層數據集和建立數據連接等工作 -
getType()
用來返回指定URI的MIME數據類型,若URI是單條數據,則返回的MIME數據類型以vnd.android.cursor.item開頭;若URI是多條數據,則返回的MIME數據類型以vnd.android.cursor.dir/開頭。 -
insert()、delete()、update()、query()
用於對數據集的增刪改查操作。
2. 聲明CONTENT_URI,實現UriMatcher
public static final String AUTHORITY = "com.example.peopleprovider";
public static final String PATH_SINGLE = "people/#";
public static final String PATH_MULTIPLE = "people";
public static final String CONTENT_URI_STRING = "content://" + AUTHORITY + "/" + PATH_MULTIPLE;
public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_STRING);
public static final int MULTIPLE_PEOPLE = 1;
public static final int SINGLE_PEOPLE = 2;
public static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, PATH_SINGLE, SINGLE_PEOPLE );
uriMatcher.addURI(AUTHORITY, PATH_MULTIPLE , MULTIPLE_PEOPLE );
}
其中UriMatcher類引用官方文檔中的解釋:
Utility class to aid in matching URIs in content providers.
可見UriMatcher本質上是一個文本過濾器,用在contentProvider中幫助我們過濾,分辨出查詢者想要查詢哪個數據表。
UriMatcher的構造函數中,UriMatcher.NO_MATCH是URI無匹配時的返回代碼,值爲-1。 addURI() 方法用來添加新的匹配項,語法爲:
public void addURI(String authority, String path, int code)
其中authority表示匹配的授權者名稱,path表示數據路徑(#代表任何數字),code表示返回代碼。
關於UriMatcher的使用:
switch(uriMatcher.match(uri)){
case MULTIPLE_PEOPLE:
//多條數據的處理
break;
case SINGLE_PEOPLE:
//單條數據的處理
break;
default:
throw new IllegalArgumentException("不支持的URI:" + uri);
}
3. 註冊ContentProvider
在AndroidManifest.xml文件中的 application節點下使用< provider >標籤註冊。示例:
<provider
android:authorities="com.example.peopleprovider"
android:name=".Peopleprovider" />
使用數據提供者
每個Android組件都有一個ContentResolver對象,通過調用getContentResolver() 方法可得到ContentResolver對象。
準備工作:ContentResolver resolver = getContentResolver();
String KEY_ID = "_id";
String KEY_NAME = "name";
String KEY_AGE = "age";
String KEY_HEIGHT = "height";
1. 添加操作
通過insert()函數添加單條數據:
(returns : the URL of the newly created row.)
ContentValues values = new ContentValues();
values.put(KEY_NAME, "Tom");
values.put(KEY_AGE, 21);
values.put(KEY_HEIGHT, 1.81f);
Uri newUri = resolver.insert(CONTENT_URI, values);
通過bulkInsert()函數添加多條數據: (returns:the number of newly created rows.)
ContentValues[] arrayValues = new ContentValues[10];
//實例化每一個ContentValues...
int count = resolver.bulkInsert(CONTENT_URI, arrayValues );
2. 刪除操作
指定ID刪除單條數據
Uri uri = Uri.parse(CONTENT_URI_STRING + "/" +"2");
int result = resolver.delete(uri, null, null);
通過selection語句刪除多條數據
String selection = KEY_ID + ">4";
int result = resolver.delete(CONTENT_URI, selection, null);
3. 更新操作
ContentValues values = new ContentValues();
values.put(KEY_NAME, "Tom");
values.put(KEY_AGE, 21);
values.put(KEY_HEIGHT, 1.81f);
Uri rui = Uri.parse(CONTENT_URI_STRING + "/" + "7");
int result = resolver.update(uri, values, null, null);
4. 查詢操作
Uri uri = Uri.parse(CONTENT_URI_STRING + "/" + "2");
Cursor cursor = resolver.query(uri, new String[]{KEY_ID, KEY_NAME, KEY_AGE, KEY_HEIGHT}, null, null, null);
在URI中定義了需要查詢數據的ID後,在query()函數中沒有必要再加入其他的查詢條件,如果要獲取數據集全部數據,則可以直接使用CONTENT_URI且不加查詢條件。
在Android系統中,數據庫查詢結果的返回值並不是數據集合的完整拷貝,而是返回數據集的指針,這個指針就是Cursor類。ContentProvider的數據集類似數據庫的數據表,其查詢結果的返回值同樣是數據集的指針:Cursor類。在提取Cursor數據中的數據前,推薦測試Cursor中的數據數量,避免在數據獲取中產生異常。示例如下:
public people[] getPeople(Cursor cursor){
int resultCounts = cursor.getCount();
if(resultCounts == 0 !cursor.moveToFirst()){
return null;
}
People[] peoples = new People[resultCounts];
for(int i=0; i<resultCounts; i++){
peoples[i] = new People();
peoples[i].ID = cursor.getInt(0);
peoples[i].Name = cursor.getString(cursor.getColumnIndex(KEY_NAME));
peoples[i].Age = cursor.getInt(cursor.getColumnIndex(KEY_AGE));
peoples[i].Height= cursor.getFloat(cursor.getColumnIndex(KEY_HEIGHT));
cursor.moveToNext();
}
return peoples;
}
其他:
1.ContentUris類使用介紹
ContentUris類用於操作Uri路徑後面的ID部分,它有兩個比較實用的方法:
withAppendedId(uri, id)用於爲路徑加上ID部分:
Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成後的Uri爲:content://com.ljq.provider.personprovider/person/10
parseId(uri)方法用於從路徑中獲取ID部分:
Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//獲取的結果爲:10
2.監聽ContentProvider中數據的變化
如果ContentProvider的訪問者需要知道ContentProvider中的數據發生變化,可以在ContentProvider發生數據變化時調用getContentResolver().notifyChange(uri,null)來通知註冊在此URI上的訪問者,例子如下:
public class PersonContentProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
db.insert("person", "personid", values);
getContext().getContentResolver().notifyChange(uri, null);
}
}
如果ContentProvider的訪問者需要得到數據變化通知,必須使用ContentObserver對數據(數據採用uri描述)進行監聽,當監聽到數據變化通知時,系統就會調用ContentObserver的onChange()方法:
getContentResolver().registerContentObserver(Uri.parse("content://com.ljq.providers.personprovider/person"),
true, new PersonObserver(new Handler()));
public class PersonObserver extends ContentObserver{
public PersonObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
//此處可以進行相應的業務處理
}
}
3.權限設置與線程同步
1. 可以在代碼中通過setReadPermission()和setWritePermission()兩個方法來設置ContentProvider的操作權限,也可以在配置文件中通過android:readPermission和android:writePermission屬性來控制。
2. 因爲ContentProvider可能被不同的進程和線程調用,所以裏面的方法必須是線程安全的。