一、簡(jiǎn)介
ContentProvider是Android四大組件之一的內(nèi)容提供器
ContentProvider為存儲(chǔ)和獲取數(shù)據(jù)提供了統(tǒng)一的接口,使用表的形式來(lái)對(duì)數(shù)據(jù)進(jìn)行封裝,使得開(kāi)發(fā)者在后續(xù)的開(kāi)發(fā)過(guò)程中不用關(guān)心數(shù)據(jù)存儲(chǔ)的細(xì)節(jié)。使用ContentProvider可以在不同的應(yīng)用程序之間共享數(shù)據(jù),Android為常見(jiàn)的數(shù)據(jù)類型提供了默認(rèn)的ContentProvider(包括音頻、視頻、圖片和通訊錄等)。
總的來(lái)說(shuō),利用ContentProvider來(lái)實(shí)現(xiàn)共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)的訪問(wèn)方式。
二、使用方法
ContentProvide的使用涉及ContentProvider、 ContentObserver、 ContentReslover 、ContentValues、Cursor、Uri、UriMatcher以及數(shù)據(jù)庫(kù)等。
ContentProvider,它最大的特點(diǎn)是可以在應(yīng)用之間共享數(shù)據(jù)
1.定義自己的ContentProvide類,
2.在AndroidManifest.xml上注冊(cè),并指定authorities屬性,給外界提供固定Uri對(duì)外提供服務(wù)
- 提供的方法
操作方法:insert、getType、delete、query、update、oncreate用于創(chuàng)建數(shù)據(jù)庫(kù)或鏈接數(shù)據(jù)庫(kù),以及提供為contentResolver增刪改查的方法。
ContentValues是用于存儲(chǔ)ContentResolver處理的值。
ContentResolver用于訪問(wèn)content模型,其實(shí)就是訪問(wèn)和操作contentprovider。
- 實(shí)現(xiàn)方式
Context提供了getContentResolver方法,這表明Activity、Service組件都可通過(guò)該方法獲取該類的實(shí)例
ContentResolver提供的操作方法:
insert、getType、delete、query、update等與ProvideContent相對(duì)應(yīng),通過(guò)Uri鏈接ContentProvide和ContentResolver
Cursor類,游標(biāo)。應(yīng)用時(shí)一般通過(guò)查詢query得到。
Uri:協(xié)議部分、域名、路徑、ID、字段
其中協(xié)議部分:content://
域名對(duì)應(yīng)authoties屬性
路徑:資源部分或數(shù)據(jù)部分
三、ContentProvider類主要方法的介紹:
public boolean onCreate(),在ContentProvider創(chuàng)建后就會(huì)被調(diào)用,而ContentProvider是在其它應(yīng)用第一次訪問(wèn)它時(shí)被創(chuàng)建;
public Uri insert(Uri uri, ContentValues values),供外部應(yīng)用向ContentProvider添加數(shù)據(jù);
public int delete(Uri uri, String selection, String[] selectionArgs),供外部應(yīng)用從ContentProvider刪除數(shù)據(jù);
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs),供外部應(yīng)用更新ContentProvider中的數(shù)據(jù);
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder),供外部應(yīng)用從ContentProvider中獲取數(shù)據(jù);
public String getType(Uri uri),返回當(dāng)前Uri所代表數(shù)據(jù)的MIME類型;
如果操作的數(shù)據(jù)屬于集合類型,那么MIME類型字符串應(yīng)該以vnd.android.cursor.dir/開(kāi)頭,如要得到所有tablename記錄的Uri為content://com.wang.provider.myprovider/tablename,那么返回的MIME類型字符串應(yīng)該為:vnd.android.cursor.dir/table。
如果要操作的數(shù)據(jù)屬于非集合類型數(shù)據(jù),那么MIME類型字符串應(yīng)該以vnd.android.cursor.item/開(kāi)頭,如得到id為10的tablename記錄,Uri為content://com.wang.provider.myprovider/tablename/10,那么返回的MIME類型字符串為:vnd.android.cursor.item/tablename 。
四、UriMatcher
Uri代表要操作的數(shù)據(jù),在開(kāi)發(fā)過(guò)程中對(duì)數(shù)據(jù)進(jìn)行獲取時(shí)需要解析Uri,Android提供了兩個(gè)用于操作Uri的工具類,分別為UriMatcher和ContentUris 。掌握它們的基本概念和使用方法,對(duì)一個(gè)Android開(kāi)發(fā)者來(lái)說(shuō)是一項(xiàng)必要的技能。
1、UriMatcher
UriMatcher類用于匹配Uri,它的使用步驟如下:
- a、將需要匹配的Uri路徑進(jìn)行注冊(cè),代碼如下:
1 //常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼
2 UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
3 //如果match()方法匹配“content://com.wang.provider.myprovider/tablename”路徑,返回匹配碼為1
4 sMatcher.addURI("content://com.wang.provider.myprovider", " tablename ", 1);
5 //如果match()方法匹配content://com.wang.provider.myprovider/tablename/11路徑,返回匹配碼為2
6 sMatcher.addURI("com.wang.provider.myprovider", "tablename/#", 2);
注意:添加第二個(gè)URI時(shí),路徑后面的id采用了通配符形式“#”,表示只要前面三個(gè)部分都匹配上了就OK。
- b、注冊(cè)完需要匹配的Uri后,可以使用sMatcher.match(Uri)方法對(duì)輸入的Uri進(jìn)行匹配,如果匹配就返回對(duì)應(yīng)的匹配碼,匹配碼為調(diào)用addURI()方法時(shí)傳入的第三個(gè)參數(shù)。
switch (sMatcher.match(Uri.parse("content://com.zhang.provider.yourprovider/tablename/100"))) {
case 1:
//match 1, todo something
break;
case 2
//match 2, todo something
break;
default:
//match nothing, todo something
break;
}
2、ContentUris
ContentUris類用于操作Uri路徑后面的ID部分,它有兩個(gè)比較實(shí)用的方法:
withAppendedId(Uri uri, long id)和parseId(Uri uri)。
withAppendedId(Uri uri, long id)用于為路徑加上ID部分:
Uri uri = Uri.parse("content://com.wang.provider.myprovider/tablename");
Uri resultUri = ContentUris.withAppendedId(uri, 10);
parseId(Uri uri)則從路徑中獲取ID部分:
Uri uri = Uri.parse("content://com.zhang.provider.myprovider/tablename/10");
long personid = ContentUris.parseId(uri);
五、ContentResolver操作數(shù)據(jù)
當(dāng)外部應(yīng)用需要對(duì)ContentProvider中的數(shù)據(jù)進(jìn)行添加、刪除、修改及查詢操作時(shí),可以使用ContentResolver 類來(lái)完成。而要獲取ContentResolver 對(duì)象,可以使用Activity提供的getContentResolver()方法。
ContentResolver 類提供了與ContentProvider類相同簽名的四個(gè)方法:
public Uri insert(Uri uri, ContentValues values),往ContentProvider添加數(shù)據(jù);
public int delete(Uri uri, String selection, String[] selectionArgs),從ContentProvider刪除數(shù)據(jù);
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs),更新ContentProvider中的數(shù)據(jù);
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder),從ContentProvider中獲取數(shù)據(jù);
這些方法的第一個(gè)參數(shù)為Uri,代表要操作的ContentProvider和對(duì)其中的什么數(shù)據(jù)進(jìn)行操作,其實(shí)和ContentProvider里面的方法是一樣的。他們所對(duì)應(yīng)的數(shù)據(jù),最終會(huì)被傳到我們?cè)谥俺绦蚶锩娑x的那個(gè)ContentProvider類的方法,假設(shè)給定的是:Uri.parse("content://com.wang.provider.myprovider/tablename/10"),那么將會(huì)對(duì)主機(jī)名為com.wang.provider.myprovider的ContentProvider進(jìn)行操作,操作的數(shù)據(jù)為tablename表中id為10的記錄。
使用ContentResolver對(duì)ContentProvider中的數(shù)據(jù)進(jìn)行操作的代碼如下:
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.wang.provider.myprovider/tablename");
//添加一條記錄
ContentValues values = new ContentValues();
values.put("name", "wang1");
values.put("age", 28);
resolver.insert(uri, values);
//獲取tablename表中所有記錄
Cursor cursor = resolver.query(uri, null, null, null, "tablename data");
while(cursor.moveToNext()){
Log.i("ContentTest", "tablename_id="+ cursor.getInt(0)+ ", name="+ cursor.getString(1));
}
//把id為1的記錄的name字段值更改新為zhang1
ContentValues updateValues = new ContentValues();
updateValues.put("name", "zhang1");
Uri updateIdUri = ContentUris.withAppendedId(uri, 2);
resolver.update(updateIdUri, updateValues, null, null);
//刪除id為2的記錄,即字段age
Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);
resolver.delete(deleteIdUri, null, null);
六、監(jiān)聽(tīng)數(shù)據(jù)變化
如果ContentProvider的訪問(wèn)者需要知道數(shù)據(jù)發(fā)生的變化,可以在ContentProvider發(fā)生數(shù)據(jù)變化時(shí)調(diào)用getContentResolver().notifyChange(uri, null)來(lái)通知注冊(cè)在此URI上的訪問(wèn)者。只給出類中監(jiān)聽(tīng)部分的代碼:
public class MyProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
db.insert("tablename", "tablenameid", values);
getContext().getContentResolver().notifyChange(uri, null);
}
}
而訪問(wèn)者必須使用ContentObserver對(duì)數(shù)據(jù)(數(shù)據(jù)采用uri描述)進(jìn)行監(jiān)聽(tīng),當(dāng)監(jiān)聽(tīng)到數(shù)據(jù)變化通知時(shí),系統(tǒng)就會(huì)調(diào)用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) {
//to do something
}
}
參考學(xué)習(xí):https://www.cnblogs.com/tgyf/p/4696288.html
寫(xiě)在最后: 本系列的文章旨在學(xué)習(xí)過(guò)程中的總結(jié),如果對(duì)你也有幫助,榮幸之至。