最近在看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的实现。本人没有写测试代码。
附上测试代码:http://pan.baidu.com/s/1i37n3Ch。