最近在看ContentProvider的知识,现在写一篇博客总结一下。实现ContentProvider必须扩展android.content.ContentProvider并实现以下重要方法:query、insert、update、delete和getType。在实现它们之前也需要进行大量设置。主要有以下几个步骤:
(1)、计划数据库、URI及列名等,创建元数据类来定义所有这些元数据元素的常量。
(2)、扩展抽象类ContentProvider。
(3)、实现方法:query、insert、update、delete和getType。
(4)、在配置文件中注册ContentProvider。
1、计划数据库
我将创建一个包含一系列图书的数据库。这个图书数据库仅包含一个books表,该表的列包括name、isbn和author。这些列名对应着元数据,这些相关的元数据将在Java类中定义。定义元数据的Java类为BookProviderMetaData,代码如下:
/** * book class * * @author Pan * */ public class BookProviderMetaData { public static final String AUTHORITY = "com.androidbook.provider.BookProvider"; public static final String DATABASE_NAME = "book.db"; public static final int DATABASE_VERSION = 1; public static final String BOOKS_TABLE_NAME = "books"; private BookProviderMetaData() { } /** * inner class describing BookTable * * @author Pan * */ public static final class BookTableMetaData implements BaseColumns { private BookTableMetaData() { } public static final String TABLE_NAME = "books"; // uri and MIME type definitions public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/books"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.androidbook.book"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.androidbook.book"; public static final String DEFAULT_SORT_ORDER = "modified DESC"; // additional column start here // string type public static final String BOOK_NAME = "name"; public static final String BOOK_ISBN = "isbn"; public static final String BOOK_AUTHOR = "author"; // Integer from System.currentTimeMillis() public static final String CREATED_DATE = "created"; public static final String MODIFIED_DATE = "modified"; } }
2、扩展ContentProvider
实现BookProvider示例ContentProvider涉及扩展ContentProvider类,重写onCreate()来创建数据库,然后实现query、insert、update、delete和getType方法。代码如下:
/** * BookProvider class * * @author Pan * */ public class BookProvider extends ContentProvider { // logging helper tag. no significance to provider private static final String TAG = "BookProvider"; // setup projection map // Projection maps are similar to "as" (column alias) construct // in an sql statement where by you can rename the columns. private static HashMap<String, String> sBooksProjectionMap; static { sBooksProjectionMap = new HashMap<String, String>(); sBooksProjectionMap.put(BookTableMetaData._ID, BookTableMetaData._ID); // name isbn author sBooksProjectionMap.put(BookTableMetaData.BOOK_NAME, BookTableMetaData.BOOK_NAME); sBooksProjectionMap.put(BookTableMetaData.BOOK_ISBN, BookTableMetaData.BOOK_ISBN); sBooksProjectionMap.put(BookTableMetaData.BOOK_AUTHOR, BookTableMetaData.BOOK_AUTHOR); // created date, modified date sBooksProjectionMap.put(BookTableMetaData.CREATED_DATE, BookTableMetaData.CREATED_DATE); sBooksProjectionMap.put(BookTableMetaData.MODIFIED_DATE, BookTableMetaData.MODIFIED_DATE); } // setup uris: provider a mechanism to identify all the incoming uri // patterns. private static final UriMatcher sUriMatcher; private static final int INCOMING_BOOK_COLLECTION_URI_INDICATOR = 1; private static final int INCOMING_SINGLE_BOOK_URI_INDICATOR = 2; static { sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(BookProviderMetaData.AUTHORITY, "books", INCOMING_BOOK_COLLECTION_URI_INDICATOR); sUriMatcher.addURI(BookProviderMetaData.AUTHORITY, "books/#", INCOMING_SINGLE_BOOK_URI_INDICATOR); } /** * setup/create database this class helps open,create,and upgrade the * database file. * * @author Pan * */ private static class DataBaseHelper extends SQLiteOpenHelper { public DataBaseHelper(Context context) { super(context, BookProviderMetaData.DATABASE_NAME, null, BookProviderMetaData.DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { Log.d(TAG, "inner oncreate called"); db.execSQL("CREATE TABLE " + BookTableMetaData.TABLE_NAME + " (" + BookTableMetaData._ID + " INTEGER PRIMARY KEY," + BookTableMetaData.BOOK_NAME + " TEXT," + BookTableMetaData.BOOK_ISBN + " TEXT," + BookTableMetaData.BOOK_AUTHOR + " TEXT," + BookTableMetaData.CREATED_DATE + " INTEGER," + BookTableMetaData.MODIFIED_DATE + " INTEGER,"); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.d(TAG, "inner onUpgrade called"); Log.w(TAG, "upgrading database from version:" + oldVersion + " to " + newVersion + ", which will destory all old data"); db.execSQL("DROP TABLE IF EXISTS " + BookTableMetaData.TABLE_NAME); onCreate(db); } } private DataBaseHelper mOpenHelper; @Override public boolean onCreate() { Log.d(TAG, "main onCreate called"); mOpenHelper = new DataBaseHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); switch (sUriMatcher.match(uri)) { case INCOMING_BOOK_COLLECTION_URI_INDICATOR: qb.setTables(BookTableMetaData.TABLE_NAME); qb.setProjectionMap(sBooksProjectionMap); break; case INCOMING_SINGLE_BOOK_URI_INDICATOR: qb.setTables(BookTableMetaData.TABLE_NAME); qb.setProjectionMap(sBooksProjectionMap); qb.appendWhere(BookTableMetaData._ID + "=" + uri.getPathSegments().get(1)); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } // if not sort order is specified use the default String orderBy; if (TextUtils.isEmpty(sortOrder)) { orderBy = BookTableMetaData.DEFAULT_SORT_ORDER; } else { orderBy = sortOrder; } // get the database and run the query SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor c = db.query(BookTableMetaData.TABLE_NAME, projection, selection, selectionArgs, null, null, orderBy); // example of getting a count @SuppressWarnings("unused") int i = c.getCount(); // tell the cursor what uri to watch, so it knows when its source data // changes c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Override public String getType(Uri uri) { switch (sUriMatcher.match(uri)) { case INCOMING_BOOK_COLLECTION_URI_INDICATOR: return BookTableMetaData.CONTENT_TYPE; case INCOMING_SINGLE_BOOK_URI_INDICATOR: return BookTableMetaData.CONTENT_ITEM_TYPE; default: throw new IllegalArgumentException("Unknown URI " + uri); } } @Override public Uri insert(Uri uri, ContentValues initialValues) { if (sUriMatcher.match(uri) != INCOMING_BOOK_COLLECTION_URI_INDICATOR) { throw new IllegalArgumentException("Unknown URI " + uri); } ContentValues values; if (initialValues != null) { values = new ContentValues(initialValues); } else { values = new ContentValues(); } Long now = Long.valueOf(System.currentTimeMillis()); // make sure that the fields are all set if (values.containsKey(BookTableMetaData.CREATED_DATE) == false) { values.put(BookTableMetaData.CREATED_DATE, now); } if (values.containsKey(BookTableMetaData.MODIFIED_DATE) == false) { values.put(BookTableMetaData.MODIFIED_DATE, now); } if (values.containsKey(BookTableMetaData.BOOK_NAME) == false) { throw new SQLException( "Failed to insert row because book name is needed " + uri); } if (values.containsKey(BookTableMetaData.BOOK_ISBN) == false) { values.put(BookTableMetaData.BOOK_ISBN, "Unknown ISBN"); } if (values.containsKey(BookTableMetaData.BOOK_AUTHOR) == false) { values.put(BookTableMetaData.BOOK_AUTHOR, "Unknown Author"); } SQLiteDatabase db = mOpenHelper.getWritableDatabase(); long rowId = db.insert(BookTableMetaData.TABLE_NAME, BookTableMetaData.BOOK_NAME, values); if (rowId > 0) { Uri insertedBookUri = ContentUris.withAppendedId( BookTableMetaData.CONTENT_URI, rowId); getContext().getContentResolver().notifyChange(insertedBookUri, null); return insertedBookUri; } throw new SQLException("Failed to insert row into " + uri); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; switch (sUriMatcher.match(uri)) { case INCOMING_BOOK_COLLECTION_URI_INDICATOR: count = db.delete(BookTableMetaData.TABLE_NAME, selection, selectionArgs); getContext().getContentResolver().notifyChange(uri, null); return count; case INCOMING_SINGLE_BOOK_URI_INDICATOR: String rowId = uri.getPathSegments().get(1); count = db.delete( BookTableMetaData.TABLE_NAME, BookTableMetaData._ID + "=" + rowId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs); getContext().getContentResolver().notifyChange(uri, null); return count; default: throw new IllegalArgumentException("Unknown URI " + uri); } } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; switch (sUriMatcher.match(uri)) { case INCOMING_BOOK_COLLECTION_URI_INDICATOR: count = db.update(BookTableMetaData.TABLE_NAME, values, selection, selectionArgs); getContext().getContentResolver().notifyChange(uri, null); return count; case INCOMING_SINGLE_BOOK_URI_INDICATOR: String rowId = uri.getPathSegments().get(1); count = db.update( BookTableMetaData.TABLE_NAME, values, BookTableMetaData._ID + "=" + rowId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs); getContext().getContentResolver().notifyChange(uri, null); return count; default: throw new IllegalArgumentException("Unknown URI " + uri); } } }
3、注册ContentProvider
在配置文件中注册BookProvider。代码如下:
<provider android:name="com.pan.contentproviderdemo.provider.BookProvider" android:authorities="com.androidbook.provider.BookProvider" />
以上就是ContentProvider的实现。本人没有写测试代码。