Android開發:ContentProvider例項詳解

weixin_33751566發表於2016-12-13
  • 2016年12月8日,Google中國開發者大會在京舉行,同時正式上線了Google中國開發者網站Google Developers,檢視官方學習資源再也不用爬梯子了
  1. 簡介
  2. 使用說明
  3. ContentObserver

簡介

ContentProvider即內容提供者,是Android的四大元件之一。內容提供者是應用程式之間共享資料的介面,Android系統將這種機制應用到方方面面。

比如:聯絡人Provider專為不同應用程式提供聯絡人資料;設定Provider專為不同應用程式提供系統配置資訊,包括內建的設定應用程式等。當應用繼承ContentProvider類,並重寫該類用於提供資料和儲存資料的方法,就可以向其他應用共享其資料。

雖然使用其他方法也可以對外共享資料,但資料訪問方式會因資料儲存的方式而不同,如:採用檔案方式對外共享資料,需要進行檔案操作讀寫資料;採用SharedPreferences共享資料,需要使用SharedPreferences API讀寫資料。

而使用ContentProvider共享資料的好處是統一了資料訪問方式。內容提供者將資料封裝,只暴露出我們希望提供給其他程式的資料。內容提供者中資料更改可被監聽。

使用說明

  1. 定義類繼承ContentProvider,根據需要重寫內部方法(增刪改查)
  2. 在清單檔案的<application>節點下進行配置,<provider>標籤中需要指定name和authorities屬性
    name:類名,包名從程式Package開始,以“.”開始
    authorities:是訪問Provider時的路徑,要唯一
  3. URI代表要操作的資料,由scheme、authorites、path三部分組成
    content://cn.gunther.sqlite.provider/person
    scheme:固定為content,代表訪問內容提供者
    authorites:<provider>節點中的authorites屬性
    path:程式定義的路徑,可根據業務邏輯定義

示例程式碼:

  1. 新建一個工程MyContentProvider,包名:com.gunther.provider。
  2. 在com.gunther.provider.dao包下新建PersonOpenHelper類繼承SQLiteOpenHelper類,該類用於建立資料庫。
    public class PersonOpenHelper extends SQLiteOpenHelper {

    public PersonOpenHelper(Context context, String name, CursorFactory factory, int version) {
        super(context, name, factory, version);
    }
    
    public PersonOpenHelper(Context context){
        super(context, "person.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table person (id integer primary key autoincrement,name varchar(20),phone varchar(20),age integer,address varchar(50));";
        db.execSQL(sql);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    }
  1. 在com.gunther.contenProvider.provider包中建立,PersonContentProvider類繼承ContentProvider類。同時將該Provider在AndroidManifest.xml中註冊。

    <provider    android:exported="true"     
    android:name="com.gunther.contenProvider.provider.PersonContentProvider"
    android:authorities="com.gunther.person" />
    
    
    
    
     public class PersonContentProvider extends ContentProvider {
     //用於存放並匹配個Uri標識資訊,一般在靜態程式碼塊中對其資訊進行初始化操作
     private static UriMatcher matcher;
     //宣告一個用於運算元據庫物件
     private PersonOpenHelper openHelper;
     //主機名資訊:對應清單檔案的authorities屬性
     private static final String AUTHORITY = "com.gunther.person";
     //資料庫 表名
     private static final String TABLE_PERSON_NAME = "person";
     //Uri匹配成功的返回碼
     private static final int PERSON_INSERT_CODE = 1000;
     private static final int PERSON_DELETE_CODE = 10001;
     private static final int PERSON_UPDATE_CODE = 10002;
     private static final int PERSON_QUERYALL_CODE = 10003;
     private static final int PERSON_QUERYONE_CODE = 10004;
     //靜態程式碼塊,用於初始化UriMatcher
     static{
         //NO_MATCH:沒有Uri匹配的時候返回的狀態碼(-1)
         matcher = new UriMatcher(UriMatcher.NO_MATCH);
         //新增一個分機號:
         //對person表進行新增操作,如果Uri=content://com.gunther.person/person/insert,則返回PERSON_INSERT_CODE
         matcher.addURI(AUTHORITY, "person/insert", PERSON_INSERT_CODE);
         //對person表進行刪除操作,如果Uri= content://com.gunther.person/person/delete,則返回PERSON_DELETE_CODE
         matcher.addURI(AUTHORITY, "person/delete", PERSON_DELETE_CODE);
         //對person表進行修改操作,如果Uri= content://com.gunther.person/person/update,則返回PERSON_UPDATE_CODE
         matcher.addURI(AUTHORITY, "person/update", PERSON_UPDATE_CODE);
         //對person表進行查詢所有操作,如果Uri= content://com.gunther.person/person,則返回PERSON_QUERYALL_CODE
         matcher.addURI(AUTHORITY, "person", PERSON_QUERYALL_CODE);
         //對person表進行查詢單個操作,如果Uri= content://com.gunther.person/person/#,(#:代表數字)則返回PERSON_QUERYONE_CODE
         matcher.addURI(AUTHORITY, "person/#", PERSON_QUERYONE_CODE);
     }
     @Override
     public boolean onCreate() {
     //內容提供者中,獲取contenxt,是通過getContext,與測試類一樣,不能再成員變數,建構函式中呼叫,但是可以再onCreate方法中獲取。
         openHelper = new PersonOpenHelper(getContext());
         return false;
     }
     @Override
     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
         //用匹配器去匹配uri,如果匹配成功則返回匹配器中對應的狀態碼
         int matchCode = matcher.match(uri);
         SQLiteDatabase db = openHelper.getReadableDatabase();
         switch (matchCode) {
         case PERSON_QUERYALL_CODE:
             return db.query(TABLE_PERSON_NAME, projection, selection, selectionArgs, null, null, sortOrder);
         case PERSON_QUERYONE_CODE:
     //使用ContentUris工具類解析出uri中的id
             long parseId = ContentUris.parseId(uri);
             return db.query(TABLE_PERSON_NAME, projection,"id=?", new String[]{parseId+""}, null, null, sortOrder);
         default:
             throw new IllegalArgumentException("Uri匹配失敗:"+uri);
         }}
     @Override
     public Uri insert(Uri uri, ContentValues values) {
         SQLiteDatabase db = openHelper.getWritableDatabase();
         //新插入物件的id
         long id = db.insert(TABLE_PERSON_NAME, null, values);
         db.close();
         //使用ContentUris工具類將id追加到uri中,返回給客戶
         return ContentUris.withAppendedId(uri, id);
     }
    
     @Override
     public int delete(Uri uri, String selection, String[] selectionArgs) {
         SQLiteDatabase db = openHelper.getWritableDatabase();
         //返回刪除的個數
         int count = db.delete(TABLE_PERSON_NAME, selection, selectionArgs);
         //關閉資料庫
         db.close();
         return count;
     }
    
     @Override
     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
         SQLiteDatabase db = openHelper.getWritableDatabase();
         //返回更新的個數
         int count = db.update(TABLE_PERSON_NAME, values, selection, selectionArgs);
         //更新資料庫
         db.close();
         return count;
     }
    
     @Override
     public String getType(Uri uri) {
         return null;
     }
    
     }
    

ContentObserver

ContentObserver——內容觀察者,目的是觀察(捕捉)特定Uri引起的資料庫的變化,繼而做一些相應的處理,它類似於資料庫技術中的觸發器(Trigger),當ContentObserver所觀察的Uri發生變化時,便會觸發它。觸發器分為表觸發器、行觸發器,相應地ContentObserver也分為“表“ContentObserver、“行”ContentObserver,當然這是與它所監聽的Uri MIME Type有關的。

private class AppLockObserver extends ContentObserver{
    public AppLockObserver(){
        super(new Handler());
    }
    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        //觀察到註冊的uri資料傳送變化,根據業務需求處理
    }
}

相關文章