ContentProvider简介
ContentProvider(數據提供者)是在應用程序間共享數據的一種接口機制 ContentProvider提供了更為高級的數據共享方法,應用程序可以指定需要共享的數據,而其他應用程序則可以在不知數據來源、路徑的情況下,對共享數據進行查詢、添加、刪除和更新等操作 許多Android系統的內置數據也通過ContentProvider提供給用戶使用,例如通訊錄、音視頻文件和圖像文件等 在創建ContentProvider時,需要首先使用數據庫、文件系統或網絡實現底層存儲功能,然后在繼承ContentProvider的類中實現基本數據操作的接口函數,包括添加、刪除、查找和更新等功能 調用者不能夠直接調用ContentProvider的接口函數,而需要使用ContentResolver對象,通過URI間接調用ContentProvider。
使用ContentProvider可以在不同的應用程序之間共享數據。 它為存儲和獲取數據提供了統一的接口。ContentProvide對數據進行封裝,不用關心數據存儲的細節。
ContentProvider不管底層數據的實際存儲方式,對外統一使用表的形式來組織數據 。
URI的簡介
Uri代表了要操作的數據,它為系統的每一個資源給其一個名字,比方說通話記錄。每一個ContentProvider都擁有一個公共的URI,這個URI用于表示這個ContentProvider所提供的數據。?
?URI的格式
A:標準前綴,用來說明一個Content Provider控制這些數據,無法改變的;"content://" ?B:URI 的標識,它定義了是哪個Content Provider提供這些數據。對于第三方應用程序,為了保證URI標識的唯一性,它必須是一個完整的、小寫的類名。這個標識在元素的 authorities屬性中說明:一般是定義該ContentProvider的包.類的名稱; "content://hx.android.text.myprovider" C:路徑,通俗的講就是你要操作的數據庫中表的名字;"content://hx.android.text.myprovider/tablename" D:如果URI中包含表示需要獲取的記錄的ID;則就返回該id對應的數據,如果沒有ID,就表示返回全部; "content://hx.android.text.myprovider/tablename/#" #表示數據id
路徑(path):可以用來表示我們要操作的數據,路徑的構建應根據業務而定,如下: ??要操作contact表中id為10的記錄,可以構建這樣的路徑:/contact/10 ??要操作contact表中id為10的記錄的name字段, contact/10/name ??要操作contact表中的所有記錄,可以構建這樣的路徑:/contact 要操作的數據不一定來自數據庫,也可以是文件等他存儲方式,如下: 要操作xml文件中contact節點下的name節點,可以構建這樣的路徑:/contact/name 如果要把一個字符串轉換成Uri,可以使用Uri類中的parse()方法,如下: Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
UriMatcher
因為Uri代表了要操作的數據,所以我們很經常需要解析Uri,并從Uri中獲取數據。Android系統提供UriMatcher ,用于匹配Uri,用法如下:? ? 1.首先把你需要匹配Uri路徑全部給注冊上,如: ?? uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1); ?? uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2); 2.注冊完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法對輸入的Uri進行匹配,如果匹配就返回匹配碼. //如果match()匹配路徑,返回匹配碼為1 ?content://com.changcheng.sqlite.provider.contactprovider/contact //如果match()匹配路徑,返回匹配碼為2 content://com.changcheng.sqlite.provider.contactprovider/contact/23
因為Uri代表了要操作的數據,所以我們經常需要解析Uri,并從Uri中獲取數據。Android系統提供了兩個用于操作Uri的工具類,分別為UriMatcher 和ContentUris 。掌握它們的使用,會便于我們的開發工作。 UriMatcher類用于匹配Uri,它的用法如下: 首先第一步把你需要匹配Uri路徑全部給注冊上,如下: //常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼 UriMatcher? sMatcher = new UriMatcher(UriMatcher.NO_MATCH); //如果match()方法匹配content://cn.itcast.provider.personprovider/person路徑,返回匹配碼為1 sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就會返回匹配碼 //如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路徑,返回匹配碼為2 sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#號為通配符 switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) { ?? case 1 ??? break; ?? case 2 ??? break; ?? default://不匹配 ??? break; } 注冊完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法對輸入的Uri進行匹配,如果匹配就返回匹配碼,匹配碼是調用addURI()方法傳入的第三個參數,假設匹配content://cn.itcast.provider.personprovider/person路徑,返回的匹配碼為1
?ContentUris類
ContentUris類用于獲取Uri路徑后面的ID部分,它有兩個比較實用的方法: withAppendedId(uri, id)用于為路徑加上ID部分: Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person") Uri resultUri = ContentUris.withAppendedId(uri, 10); //生成后的Uri為:content://cn.itcast.provider.personprovider/person/10
parseId(uri)方法用于從路徑中獲取ID部分: Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10") long personid = ContentUris.parseId(uri);//獲取的結果為:10
ContentProvider的編程方法
程序開發人員通過繼承ContentProvider類可以創建一個新的數據提供者,過程可以分為三步 1.繼承ContentProvider,并重載六個函數 public boolean onCreate() 該方法在ContentProvider創建后就會被調用, Android開機后, ContentProvider在其它應用第一次訪問它時才會被創建。 public Uri insert(Uri uri, ContentValues values) 該方法用于供外部應用往ContentProvider添加數據。 public int delete(Uri uri, String selection, String[] selectionArgs) 該方法用于供外部應用從ContentProvider刪除數據。 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 該方法用于供外部應用更新ContentProvider中的數據。 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 該方法用于供外部應用從ContentProvider中獲取數據。 public String getType(Uri uri) 該方法用于返回當前Url所代表數據的MIME類型。如果操作的數據屬于集合類型,那么MIME類型字符串應該以vnd.android.cursor.dir/開頭,例如:要得到所有person記錄的Uri為content://cn.itcast.provider.personprovider/person,那么返回的MIME類型字符串應該為:“vnd.android.cursor.dir/person”。如果要操作的數據屬于非集合類型數據,那么MIME類型字符串應該以vnd.android.cursor.item/開頭,例如:得到id為10的person記錄,Uri為content://cn.itcast.provider.personprovider/person/10,那么返回的MIME類型字符串應該為:“vnd.android.cursor.item/person”。
2.聲明CONTENT_URI,實現UriMatcher 3.注冊ContentProvider? AndroidManifest.xml使用<provider>對該ContentProvider進行配置,為了能讓其他應用找到該ContentProvider , ContentProvider 采用了authorities(主機名/域名)對它進行唯一標識,你可以把 ContentProvider看作是一個網站(想想,網站也是提供數據者),authorities 就是他的域名:
<application android:icon="@drawable/icon" android:label="@string/app_name"> ?<provider android:name = ".PeopleProvider" ???android:authorities = "edu.hrbeu.peopleprovider"/> </application>
注意:一旦應用繼承了ContentProvider類,后面我們就會把這個應用稱為ContentProvider(內容提供者)。
ContentResolver的編程方法
使用ContentProvider是通過Android組件都具有的ContentResolver對象,通過URI進行數據操作 程序開發人員只需要知道URI和數據集的數據格式,則可以進行數據操作,解決不同應用程序之間的數據共享問題 每個Android組件都具有一個ContentResolver對象,獲取ContentResolver對象的方法是調用getContentResolver()函數
使用ContentResolver操作ContentProvider中的數據
當外部應用需要對ContentProvider中的數據進行添加、刪除、修改和查詢操作時,可以使用ContentResolver 類來完成,要獲取ContentResolver 對象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 類提供了與ContentProvider類相同簽名的四個方法: public Uri insert(Uri uri, ContentValues values) 該方法用于往ContentProvider添加數據。 public int delete(Uri uri, String selection, String[] selectionArgs) 該方法用于從ContentProvider刪除數據。 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 該方法用于更新ContentProvider中的數據。 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 該方法用于從ContentProvider中獲取數據。
這些方法的第一個參數為Uri,代表要操作的ContentProvider和對其中的什么數據進行操作,假設給定的是: Uri.parse(“content://cn.itcast.providers.personprovider/person/10”),那么將會對主機名為cn.itcast.providers.personprovider的ContentProvider進行操作,操作的數據為person表中id為10的記錄。
使用ContentResolver對ContentProvider中的數據進行添加、刪除、修改和查詢操作: ContentResolver resolver =? getContentResolver(); Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person"); //添加一條記錄 ContentValues values = new ContentValues(); values.put("name", "itcast"); values.put("age", 25); resolver.insert(uri, values);?? //獲取person表中所有記錄 Cursor cursor = resolver.query(uri, null, null, null, "personid desc"); while(cursor.moveToNext()){ ?Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ cursor.getString(1)); } //把id為1的記錄的name字段值更改新為liming ContentValues updateValues = new ContentValues(); updateValues.put("name", "liming"); Uri updateIdUri = ContentUris.withAppendedId(uri, 2); resolver.update(updateIdUri, updateValues, null, null); //刪除id為2的記錄 Uri deleteIdUri = ContentUris.withAppendedId(uri, 2); resolver.delete(deleteIdUri, null, null);
當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://cn.itcast.providers.personprovider/person"), ??????? ??true, new PersonObserver(new Handler())); public class PersonObserver extends ContentObserver{ ?public PersonObserver(Handler handler) { ??super(handler); ??} ?public void onChange(boolean selfChange) { ???? //此處可以進行相應的業務處理 ?} }
具體一個例子代碼:
View Code
?import cn.itcast.service.DBOpenHelper;
?import android.content.ContentProvider;
?import android.content.ContentUris;
?import android.content.ContentValues;
?import android.content.UriMatcher;
?import android.database.Cursor;
?import android.database.sqlite.SQLiteDatabase;
?import android.net.Uri;
?
?public class PersonProvider extends ContentProvider {
???? private DBOpenHelper dbOpenHelper;
???? //常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼
???? private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
???? private static final int PERSONS = 1;
???? private static final int PERSON = 2;
???? static{
???????? //如果match()方法匹配content://cn.itcast.provider.personprovider/person路徑,返回匹配碼為1
???????? MATCHER.addURI("cn.itcast.providers.personprovider", "person", PERSONS);
???????? //如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路徑,返回匹配碼為2
???????? MATCHER.addURI("cn.itcast.providers.personprovider", "person/#", PERSON);
???? }???
???? //刪除person表中的所有記錄?? /person
?//刪除person表中指定id的記錄 /person/10
???? @Override
???? public int delete(Uri uri, String selection, String[] selectionArgs) {
???????? SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
???????? int count = 0;
???????? switch (MATCHER.match(uri)) {
???????? case PERSONS:
???????????? count = db.delete("person", selection, selectionArgs);
???????????? return count;
????????????
???????? case PERSON:
???????????? long id = ContentUris.parseId(uri);
???????????? String where = "personid="+ id;
???????????? if(selection!=null && !"".equals(selection)){
???????????????? where = selection + " and " + where;
???????????? }
???????????? count = db.delete("person", where, selectionArgs);
???????????? return count;
????????????
???????? default:
???????????? throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
???????? }
???? }
?
???? @Override
???? public String getType(Uri uri) {//返回當前操作的數據的mimeType
???????? switch (MATCHER.match(uri)) {
???????? case PERSONS:??? //多條數據???????
???????????? return "vnd.android.cursor.dir/person";
????????????
???????? case PERSON:??? //單條數據???????
???????????? return "vnd.android.cursor.item/person";
????????????
???????? default:
???????????? throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
???????? }
???? }
?
???? @Override
???? public Uri insert(Uri uri, ContentValues values) {// /person
???????? SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
???????? switch (MATCHER.match(uri)) {
???????? case PERSONS:
???????????? long rowid = db.insert("person", "name", values);
???????????? //生成后的Uri為:content://cn.itcast.provider.personprovider/person/10
???????????? Uri insertUri = ContentUris.withAppendedId(uri, rowid);//得到代表新增記錄的Uri
?//當ContentProvider中的數據發生變化時可以向其用戶發出通知,第一個參數為uri,說明是person表的uri,不是單條記錄的uri
???????????? this.getContext().getContentResolver().notifyChange(uri, null);
???????????? return insertUri;
?
???????? default://不匹配
???????????? throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
???????? }
???? }
?
???? @Override
???? public boolean onCreate() {
???????? this.dbOpenHelper = new DBOpenHelper(this.getContext());
???????? return false;
???? }
???? //查詢person表中的所有記錄?? /person
?//查詢person表中指定id的記錄 /person/10
???? @Override
???? public Cursor query(Uri uri, String[] projection, String selection,
???????????? String[] selectionArgs, String sortOrder) {
???????? SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
???????? switch (MATCHER.match(uri)) {
???????? case PERSONS:
???????????? return db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
????????????
???????? case PERSON:
???????????? long id = ContentUris.parseId(uri);
???????????? String where = "personid="+ id;
???????????? if(selection!=null && !"".equals(selection)){
???????????????? where = selection + " and " + where;
???????????? }
???????????? return db.query("person", projection, where, selectionArgs, null, null, sortOrder);
????????????
???????? default:
???????????? throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
???????? }
???? }
????
???? //更新person表中的所有記錄?? /person
?//更新person表中指定id的記錄 /person/10
???? @Override
???? public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
???????? SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
???????? int count = 0;
???????? switch (MATCHER.match(uri)) {
???????? case PERSONS:
???????????? count = db.update("person", values, selection, selectionArgs);
???????????? return count;
????????????
???????? case PERSON:
???????????? //parseId(uri)方法用于從路徑中獲取ID部分:獲取的結果為:10
???????????? long id = ContentUris.parseId(uri);
???????????? String where = "personid="+ id;
???????????? //如果外面傳進來的條件不為空,而且不為空字符串
???????????? if(selection!=null && !"".equals(selection)){
???????????????? //外面的條件加自己的條件
???????????????? where = selection + " and " + where;
???????????? }
???????????? count = db.update("person", values, where, selectionArgs);
???????????? return count;
????????????
???????? default:
???????????? throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
???????? }
???? }
?
?}
AndroidMainFest.xml代碼
View Code
?<?xml version="1.0" encoding="utf-8"?>
?<manifest xmlns:android="http://schemas.android.com/apk/res/android"
?????? package="cn.itcast.db"
?????? android:versionCode="1"
?????? android:versionName="1.0">
???? <application android:icon="@drawable/icon" android:label="@string/app_name">
????????? <uses-library android:name="android.test.runner" />
???????? <activity android:name=".MainActivity"
?????????????????? android:label="@string/app_name">
???????????? <intent-filter>
???????????????? <action android:name="android.intent.action.MAIN" />
???????????????? <category android:name="android.intent.category.LAUNCHER" />
???????????? </intent-filter>
???????? </activity>
???????? <provider android:name=".PersonProvider" android:authorities="cn.itcast.providers.personprovider"/>
???? </application>
???? <uses-sdk android:minSdkVersion="8" />
?<instrumentation android:name="android.test.InstrumentationTestRunner"
?? android:targetPackage="cn.itcast.db" android:label="Tests for My App" />
?</manifest>
另一個應用程序調用ContentProvider
View Code
?import android.content.ContentResolver;
?import android.content.ContentValues;
?import android.database.Cursor;
?import android.net.Uri;
?import android.test.AndroidTestCase;
?import android.util.Log;
?
?public class AccessContentProviderTest extends AndroidTestCase {
???? private static final String TAG = "AccessContentProviderTest";
????
???? /**
????? * 往內容提供者添加數據
????? * @throws Throwable
?*/
???? public void testInsert() throws Throwable{
???????? ContentResolver contentResolver = this.getContext().getContentResolver();
???????? Uri insertUri = Uri.parse("content://cn.itcast.providers.personprovider/person");
???????? ContentValues values = new ContentValues();
???????? values.put("name", "zhangxiaoxiao");
???????? values.put("amount", 90);
???????? Uri uri = contentResolver.insert(insertUri, values);
???????? Log.i(TAG, uri.toString());
???? }
?
???? /**
????? * 更新內容提供者中的數據
????? * @throws Throwable
?*/
???? public void testUpdate() throws Throwable{
???????? ContentResolver contentResolver = this.getContext().getContentResolver();
???????? Uri updateUri = Uri.parse("content://cn.itcast.providers.personprovider/person/1");
???????? ContentValues values = new ContentValues();
???????? values.put("name", "lili");
???????? contentResolver.update(updateUri, values, null, null);
???? }
????
???? /**
????? * 從內容提供者中刪除數據
????? * @throws Throwable
?*/
???? public void testDelete() throws Throwable{
???????? ContentResolver contentResolver = this.getContext().getContentResolver();
???????? Uri deleteUri = Uri.parse("content://cn.itcast.providers.personprovider/person/1");
???????? contentResolver.delete(deleteUri, null, null);
???? }
????
???? /**
????? * 獲取內容提供者中的數據
????? * @throws Throwable
?*/
???? public void testFind() throws Throwable{
???????? ContentResolver contentResolver = this.getContext().getContentResolver();
???????? Uri selectUri = Uri.parse("content://cn.itcast.providers.personprovider/person");
???????? Cursor cursor = contentResolver.query(selectUri, null, null, null, "personid desc");
???????? while(cursor.moveToNext()){
???????????? int id = cursor.getInt(cursor.getColumnIndex("personid"));
???????????? String name = cursor.getString(cursor.getColumnIndex("name"));
???????????? int amount = cursor.getInt(cursor.getColumnIndex("amount"));
???????????? Log.i(TAG, "id="+ id + ",name="+ name+ ",amount="+ amount);
???????? }
???? }
?}
總結
以上是生活随笔為你收集整理的ContentProvider简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: quartz2d 实现太极图
- 下一篇: 找回显示桌面图标