Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver
interface. A content provider is only required if you need to share data between multiple applications. If you don't need to share data amongst multiple applications you can use a database directly via SQLiteDatabase
.
照我的理解的话,你可以把ContentProvider 当成是一个适配器。 也就是让应用程序能够通过Content provider提供的接口,调用database 提供的接口来访问database中的数据。也就是说用户可以直接使用ContentResolver操作ContentProvider 来间接访问其它应用程序存在database 中的数据。
下面的例子是实现了这个过程。
一 实现custom content provider
public class ReadingProvider extends ContentProvider {
public static final String AUTHORITY = ReadingProvider.class.getName().toLowerCase();
//下面是定义了两个访问类型的常量。
//访问整张数据表
private static final int TYPE_ALL_ITEMS = 1;
//访问该张表中特定的row的数据
private static final int TYPE_SINGLE_ITEM = 2;
//这个contentprovider对应的数据库
private ReadingOpenHelper dbhelper = null;
//用来匹配content provider的 Uri
private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
matcher.addURI(AUTHORITY, "items", TYPE_ALL_ITEMS);
//注意这个# 的意思是占位符,对应的uri可以是这样的形式
//static final Uri URI = Uri.parse("content://" + ReadingProvider.AUTHORITY + "/items");
//itemUri = Uri.withAppendedPath(URI, "" + item_id);
matcher.addURI(AUTHORITY, "items/#", TYPE_SINGLE_ITEM);
}
//在这个content provider创建的时候打开数据库
@Override
public boolean onCreate() {
log.debug("readingprovider oncreate");
dbhelper = new ReadingOpenHelper(getContext());
return true;
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
switch (matcher.match(uri)) {
case TYPE_ALL_ITEMS:
//当匹配TYPE_ALL_ITEMS 这个Uri的时候就删掉ItemColumns.TABLE_NAME 这个table中相应的数据
return dbhelper.getWritableDatabase().delete(ItemColumns.TABLE_NAME, where, whereArgs);
case TYPE_SINGLE_ITEM:
//当匹配TYPE_SINGLE_ITEM 这个Uri的时候就删掉ItemColumns.TABLE_NAME 这个table中用id指定的row的数据
String i_id = uri.getPathSegments().get(1);
return dbhelper.getWritableDatabase().delete(ItemColumns.TABLE_NAME, ItemColumns._ID + "=" + i_id, null);
}
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
@Override
public String getType(Uri uri) {
switch (matcher.match(uri)) {
case TYPE_ALL_ITEMS:
return null;//there is no type so return null
case TYPE_SINGLE_ITEM:
return null;
}
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
long id = 0L;
switch (matcher.match(uri)) {
case TYPE_ALL_ITEMS:
//当匹配这个Uri的时候就在(ItemColumns.TABLE_NAME这个table中插入initialValues
id = dbhelper.getWritableDatabase().insertOrThrow(ItemColumns.TABLE_NAME, null, initialValues);
return ContentUris.withAppendedId(ItemColumns.URI, id);
}
throw new IllegalArgumentException("Illegal Uri: " + uri.toString());
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sort) {
//log.debug("reading provider query" + uri.toString());
Cursor cursor = null;
switch (matcher.match(uri)) {
case TYPE_ALL_ITEMS:
cursor = dbhelper.getReadableDatabase().query(ItemColumns.TABLE_NAME, projection, selection, selectionArgs, null, null, sort);
break;
case TYPE_SINGLE_ITEM:
String i_id = uri.getPathSegments().get(1);
cursor = dbhelper.getReadableDatabase().query(ItemColumns.TABLE_NAME, projection, ItemColumns._ID + "=" + i_id, null, null, null, null);
break;
default:
throw new IllegalArgumentException("Illegal Uri: " + uri.toString());
}
if (cursor != null) {
cursor.setNotificationUri(getContext().getContentResolver(), uri);
} else {
log.warn("query failed in reading provider");
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues initialValues, String where, String[] whereArgs) {
switch (matcher.match(uri)) {
case TYPE_ALL_ITEMS:
return dbhelper.getWritableDatabase().update(ItemColumns.TABLE_NAME, initialValues, where, whereArgs);
}
throw new IllegalArgumentException("Illegal Uri: " + uri.toString());
}
}
note: 由上面的content provider的实现我们可以看到,content provider的内部都是在对其相关联的那个数据库进行操作。
二 下面实现这个数据库。 ReadingOpenHelper 继承 SQLiteOpenHelper,使用父类提供的接口来对自己定义的数据库进行相关的操作
1.
public class ReadingOpenHelper extends SQLiteOpenHelper {
private final Log log = Utils.getLog(getClass());
public ReadingOpenHelper(Context context) {
super(context, "bereader.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
//下面是创建一个数据库的sql语句
String sql_create_item = cat(
"CREATE TABLE IF NOT EXISTS ", ItemColumns.TABLE_NAME, " (",
ItemColumns._ID, " INTEGER PRIMARY KEY AUTOINCREMENT, ",
ItemColumns.TITLE, " VARCHAR(256)"
");"
);
String sql_index_item_title = cat(
"CREATE UNIQUE INDEX IDX_",
ItemColumns.TABLE_NAME,
"_",
ItemColumns.TITLE,
" ON ",
ItemColumns.TABLE_NAME,
" (",
ItemColumns.TITLE,
");"
);
//执行这个sql语句
db.execSQL(sql_create_item);
db.execSQL(sql_index_item_title);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
log.debug("onUpdate, from: " + oldVersion + " to " + newVersion);
if (oldVersion!=newVersion) {
// drop db 更新数据库的时候要先删掉以前的数据库,这里我们调用onCreate(db);
//来重新生成一个数据库
db.execSQL(cat("DROP TABLE ", ItemColumns.TABLE_NAME));
onCreate(db);
}
}
String cat(String... ss) {
StringBuilder sb = new StringBuilder(ss.length << 3);
for (String s : ss)
sb.append(s);
return sb.toString();
}
}
2.下面这个类就是表示数据库中的一个一个item实体,定义了这个item所在的数据表的名字,用来访问这个数据表的Uri,和这个item的field 这里只有一个TITLE
public interface ItemColumns extends BaseColumns {
//用这个Uri就能够从provider中访问数据库中存储的ItemColumns 的内容
static final Uri URI = Uri.parse("content://" + ReadingProvider.AUTHORITY + "/items");
static final String TABLE_NAME = "beReaderItems";
static final String TITLE = "title";
}
三: 下面我们来使用content provider来访问数据库中的数据。
void testProvider(){
ContentValues cv = new ContentValues();
ContentResolver cr = getContentResolver();
cv.put(ItemColumns.TABLE_NAME, "title_name1");
//插入一条item
cr.insert(ItemColumns.URI,cv);
//查询指定的item
String itemUri = Uri.withAppendedPath(ItemColumns.URI, "" + item_id);
Cursor cursor = cr.query(itemUri,
new String [] {ItemColumns._ID,ItemColumns.TITLE,},
null, null, null);
//更新一条记录
cv.put(ItemColumns.TABLE_NAME, "title_name1");
int n = cr.update(
ItemColumns.URI,
cv,
ItemColumns.URI._ID + "=" + itemId,
null
);
}