提供了統一對外的數據訪問接口,能夠把本身應用的數據提供出去給的應用程序使用,能夠對你的數據進行增刪改查,例如 通信錄就是其中的一種。java
要想建立一個 Content Provider 須要進行下面幾部操做:android
<provider android:name="classpath" android:authorities="com.exmaple.provider.applicationname" />
Public static final Uri CONTENT_URI = Uri.parse("content://com.exmaple.provider.applicationname/elements")
經過 Android 中的 Uri 訪問 Content Provider,Uri主要包含下面幾部分:content://com.example.earthquake/contentprovider/quakes/1
數據庫
咱們通常提供所有查詢和指定條數兩種支持查詢模式:其中一個很是有用的類 UriMatcher,它是一個很是有用的類,能夠分析 URI 並肯定它的形勢。數據結構
// 建立兩個常量來區分不一樣的 URI 請求 private static final int ALLROWS = 1; private static final int SINGLE_ROW = 2; private static final UriMatcher uriMatcher; // 填充 UriMatcher 對象,其中 element 結尾的 URI 對應請求全部的數據 // 以 elements/rowid 結尾的 URI 表明請求單行數據 static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.exmaple.message.provider", "elements", ALLROWS); uriMatcher.addURI("com.exmaple.message.provider", "elements/#", SINGLE_ROW); }
在同一個 Content Provider 中,可使用一樣的技術來公開其餘的 URI,這些 URI 表明了不一樣的數據子集或數據庫中不一樣的表。app
區分了全表和單行查詢後,就能夠很容易的使用 SQLiteQueryBuilder 類對一個查詢應用額外的選擇條件,以下面的代碼所示:ide
SQLiteQueryBuilder sqb = new SQLiteQueryBuilder(); // 若是是行查詢,用傳入的行限制結果集 switch (uriMatcher.match(uri)) { case SINGLE_ROW: String rowID = uri.getPathSegments().get(1); sqb.appendWhere(KEY_ID + "=" + rowID); default: break; }
經常使用幫助方法:ui
UriMatcher:用於匹配對應的 Uri 路徑
ContentUris:用於操做 Uri 路徑後面的 id 部分spa
當應用程序啓動時,每一個 Content Provider 的 onCreate 處理程序會再應用程序的主線程中被調用。
和以前的數據庫操做同樣,最好使用 SQLiteOpenHelper 來延遲打開(必要的地方建立)底層的數據庫,直到 Content Provider 的查詢或事務方法須要時再打開或建立它。線程
@Override public boolean onCreate() { // 構建一個底層數據庫 // 延遲打開數據庫,直到須要執行 // 一個查詢或者事務時再打開 sqLiteHelper = new MessageSQLiteHelper(getContext(), MessageSQLiteHelper.DATABASE_NAME, null, MessageSQLiteHelper.DATABASE_VERSION); return true; }
要想使用 Content Provider 就必須實現 query 和 getType 方法。Content Provider 使用這些方法來訪問底層數據,無需知道底層的數據結構和實現。
Content Provider 的最多見場景就是訪問一個 SQLite 數據庫,但在這些方法中,你能夠訪問任何的數據庫(包括文件或應用程序實例變量)。
UriMatcher 對象應用於完善事務處理和查詢請求,而 SQLiteQueryBuilder 是執行基於行查詢的便利輔助類。code
public class StudentContentProvider extends ContentProvider { private SimpleSQLiteHelper sqLiteHelper; // 建立兩個常量來區分不一樣的 URI 請求 public static final int ALLROWS = 1; public static final int SINGLE_ROW = 2; public static final Uri CONTENT_URI = Uri.parse("content://com.example.contentprovider/students"); private static final UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.example.contentprovider", "students", ALLROWS); uriMatcher.addURI("com.example.contentprovider", "students/#", SINGLE_ROW); } @Override public boolean onCreate() { sqLiteHelper = new SimpleSQLiteHelper(getContext(), SimpleSQLiteHelper.DATABASE_NAME, null, SimpleSQLiteHelper.DATABASE_VERSION); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db; try { db = sqLiteHelper.getWritableDatabase(); } catch (SQLiteException e) { db = sqLiteHelper.getReadableDatabase(); } // 設定分組和聚合條件 String groupBy = null; String having = null; SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); switch (uriMatcher.match(uri)) { case SINGLE_ROW: String rowID = uri.getPathSegments().get(1); queryBuilder.appendWhere(SimpleSQLiteHelper.KEY_ID + " = " + rowID); break; default: break; } // 指定要執行查詢的表,根據須要,這能夠是一個特定的表或者一個鏈接 queryBuilder.setTables(SimpleSQLiteHelper.DATABASE_TABLE); // 執行查詢操做 Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, groupBy, having, sortOrder); return cursor; } @Override public String getType(Uri uri) { // 爲一個 Content Provider URI 返回一個字符串,它標識了 MIME 類型 switch (uriMatcher.match(uri)) { case ALLROWS: return "vnd.android.cursor.dir/vnd.example.contentprovider.elemental"; case SINGLE_ROW: return "vnd.android.cursor.item/vnd.example.contentprovider.elemental"; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } @Override public Uri insert(Uri uri, ContentValues values) { // 打開一個可寫的數據庫鏈接 SQLiteDatabase db = sqLiteHelper.getWritableDatabase(); String nullColumnHack = null; // 向表中插入值 long id = db.insert(SimpleSQLiteHelper.DATABASE_TABLE, nullColumnHack, values); if (id > -1) { // 構造並返回插入行的 URI Uri insertedId = ContentUris.withAppendedId(CONTENT_URI, id); // 通知全部的觀察者,數據集已經改變 getContext().getContentResolver().notifyChange(insertedId, null); return insertedId; } return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // 打開一個可寫的數據庫鏈接 SQLiteDatabase db = sqLiteHelper.getWritableDatabase(); // 若是是行 URI,限定刪除行爲指定的行 switch (uriMatcher.match(uri)) { case SINGLE_ROW: String rowID = uri.getPathSegments().get(1); selection = SimpleSQLiteHelper.KEY_ID + " = " + rowID + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : ""); break; default: break; } // 要想返回刪除的項的數量,必須指定一條 where 子句,要刪除全部的行並返回一個值,則傳入 1 if (selection == null) { selection = "1"; } // 執行刪除操做 int deleteCount = db.delete(SimpleSQLiteHelper.DATABASE_TABLE, selection, selectionArgs); // 通知全部的觀察者,數據集已經改變 getContext().getContentResolver().notifyChange(uri, null); return deleteCount; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // 打開一個可寫的數據庫鏈接 SQLiteDatabase db = sqLiteHelper.getWritableDatabase(); // 若是是行 URI,限定刪除行爲指定的行 switch (uriMatcher.match(uri)) { case SINGLE_ROW: String rowID = uri.getPathSegments().get(1); selection = SimpleSQLiteHelper.KEY_ID + " = " + rowID + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : ""); break; default: break; } // 執行更新 int updateCount = db.update(SimpleSQLiteHelper.DATABASE_TABLE, values, selection, selectionArgs); // 通知全部的觀察者,數據集已經改變 getContext().getContentResolver().notifyChange(uri, null); return updateCount; } }
能夠經過 Content Resolver 來訪問 Content Provider 提供的數據。能夠經過 getContext().getContentResolver()
方法來獲取一個 Content Resolver 對象。
若是 共享的數據發生變化,能夠在 Content Provider 發生數據變化時調用 getCotentResolver().notifyChange(uri, null)
來通知註冊在此 URI 上的訪問者