在在Content provider實現中使用SQLiteOpenHelper中實現的是特別簡單的content provider,方法實現不全。下面給出一個實現比較全面的Content provider,當然也是很簡單的。
使用UriMatcher
UriMatcher可以幫助開發者識別Uri。比如:
content://com.easymorse.cp.mycp/emperors
表示獲取朝代列表集合。而:
content://com.easymorse.cp.mycp/emperors/1
表示其中的_ID值爲1的一個特定的記錄。
如果自己寫分析Uri的代碼,比較繁瑣和重複。android提供了方便的工具類UriMatcher。
首先定義兩個常量,針對集合與特定的單條記錄:
private static final int ITEMS = 1;
private static final int ITEM = 2;
另外要創建UriMatcher實例:
private static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, TABLE_EMPERORS, ITEMS);
uriMatcher.addURI(PROVIDER_NAME, TABLE_EMPERORS + "/#", ITEM);
}
靜態即可。然後在靜態初始化塊中把ITEMS和ITEM加進去。這裏指定了ITEMS的URI模式是:
content://com.easymorse.cp.mycp/emperors
而ITEM是:
content://com.easymorse.cp.mycp/emperors/#
#號表示一個id值。
UriMatcher如何使用呢?
uriMatcher.match(uri)
如果一個content://com.easymorse.cp.mycp/emperors Uri,該方法將返回1,也就是常量ITEMS的值,以此類推。
編寫一個getType方法:
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case ITEMS:
return "vnd.android.cursor.dir/vnd.easymorse.mycp";
case ITEM:
return "vnd.android.cursor.item/vnd.easymorse.mycp";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
這個方法在本例中並未起到作用,如果作爲intent並使用data(Mimetype)就會用到這個方法。可見總結一下Intent概念的data測試部分。
編寫查詢方法
查詢方法的代碼:
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (uriMatcher.match(uri)) {
case ITEMS:
return database.query(TABLE_EMPERORS, projection, selection,
selectionArgs, null, null, sortOrder);
case ITEM:
return database.query(TABLE_EMPERORS, projection, _ID + "="
+ uri.getPathSegments().get(1), selectionArgs, null, null,
null);
default:
throw new IllegalArgumentException("unknown uri: " + uri);
}
}
這裏有兩種可能,通過條件查詢,或者通過id查詢,前者走ITEMS,後者走ITEM,都是通過Uri判斷的,藉助UriMatcher。這裏:
uri.getPathSegments().get(1),
將取到id號。如果get(0),將取到path的第一個值emperors。
使用該Content provider的代碼:
private String getContentProviderValues() {
StringBuilder builder = new StringBuilder();// 查名稱和朝代,朝代=明,而且按照登基時間倒排序
Cursor cursor = managedQuery(MyContentProvider.CONTENT_URI,
new String[] { MyContentProvider.NAME,
MyContentProvider.DYNASTY }, MyContentProvider.DYNASTY
+ "=?", new String[] { "明" }, " start_year desc");// 查全部記錄
// Cursor cursor = managedQuery(MyContentProvider.CONTENT_URI, null,
// null,
// null, null);// 根據id定位記錄(0..1)
// Cursor cursor = managedQuery(ContentUris.withAppendedId(
// MyContentProvider.CONTENT_URI, 1),
// new String[] { MyContentProvider.NAME }, null, null, null);while (cursor.moveToNext()) {
builder
.append(
cursor.getString(cursor
.getColumnIndex(MyContentProvider.NAME)))
.append(" | ")
// .append(
// cursor
// .getString(cursor
// .getColumnIndex(MyContentProvider.START_YEAR)))
// .append(" | ")
.append(
cursor.getString(cursor
.getColumnIndex(MyContentProvider.DYNASTY)))
.append("/n");
}
可以有多種使用方式,本例中屏蔽部分,是其他使用方式。
編寫編輯方法
insert()、update()和delete()都屬於編輯記錄的功能。拿update舉例,因爲比較複雜一點:
@Override
public int update(Uri uri, ContentValues contentValues, String selection,
String[] selectionArgs) {
switch (uriMatcher.match(uri)) {
case ITEM:
return database.update(TABLE_EMPERORS, contentValues,
_ID + "=" + uri.getPathSegments().get(1) + " and ("
+ selection + ")", selectionArgs);
case ITEMS:
return database.update(TABLE_EMPERORS, contentValues, selection,
selectionArgs);
default:
throw new IllegalArgumentException("unknown uri: " + uri);
}
}
這裏複雜的地方是如果根據id做修改,比如還有其他附加條件,需要拼接where子句字符串。後面的and要帶括號,否則邏輯可能不同。
使用這個Content provider的做update的示例:
ContentValues values = new ContentValues();
values.put(MyContentProvider.NAME, "朱重八");
getContentResolver().update(MyContentProvider.CONTENT_URI, values,
MyContentProvider.NAME + "=?", new String[] { "朱元璋" });
修改表中是朱元璋的,改爲他的小名,朱重八。
如果是delete和insert操作,情況是類似的。
完整示例見:
http://easymorse.googlecode.com/svn/tags/content.provider-0.3.0/
相關日誌
轉:http://marshal.easymorse.com/archives/2991