contentprovider總結

轉載博客: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描述)進行監聽,當監聽到數據變化通知時,系統就會調用ContentObserveronChange()方法:

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可能被不同的進程和線程調用,所以裏面的方法必須是線程安全的。








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章