ContentProvider
内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能.
Android系统中自带的电话簿、短信、媒体库等程序都提供了类似的访问接口,这就使得第三方应用程序可以充分地利用这部分数据来实现更好的功能。
通过 Context 中的 getContentResolver()方法获取到该类的实例。
ContentResolver中的增删改查方法都是不接收表名参数的,而是使用一个 Uri参数代替,这个参数被称为内容 URI。
URI最标准的格式写法如下:
content://com.example.app.provider/table1
content://com.example.app.provider/table2
在得到了内容 URI 字符串之后,我们还需要将它解析成 Uri对象才可以作为参数传入。
Uri uri = Uri.parse(“content://com.example.app.provider/table1”)
只需要调用 Uri.parse()方法,就可以将内容 URI 字符串解析成 Uri对象了。
有了URI对象我们就可以操作了:
getContentResolver().delete(uri, “column2 = ?”, new String[] { “1” });
创建自己的内容提供器
1.继承 ContentProvider的方式来创建一个自己的内容提供器。
ContentProvider类中有六个抽象方法,
public class MyContentProvider extends ContentProvider {
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return null;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return 0;
}
}
- onCreate()
初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回 true 表示内容提供器初始化成功,返回 false 则表示失败。注意,只有当存在ContentResolver尝试访问我们程序中的数据时,内容提供器才会被初始化。 - query()
从内容提供器中查询数据。使用 uri参数来确定查询哪张表,projection 参数用于确定查询哪些列,selection 和 selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在 Cursor对象中返回。 - insert()
向内容提供器中添加一条数据。使用 uri参数来确定要添加到的表,待添加的数据保存在 values 参数中。添加完成后,返回一个用于表示这条新记录的 URI。 - update()
更新内容提供器中已有的数据。使用 uri参数来确定更新哪一张表中的数据,新数据保存在 values 参数中,selection 和 selectionArgs参数用于约束更新哪些行,受影响的行数将作为返回值返回。 - delete()
从内容提供器中删除数据。使用 uri 参数来确定删除哪一张表中的数据,selection和 selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。 getType()
根据传入的内容 URI 来返回相应的 MIME 类型。
MIME字符串主要由三部分组分,Android对这三个部分做了如下格式规定。1. 必须以 vnd 开头。 2. 如果内容 URI 以路径结尾,则后接 android.cursor.dir/,如果内容 URI 以 id 结尾,则后接 android.cursor.item/。 3. 最后接上 vnd.<authority>.<path>。
所以,对于 content://com.example.app.provider/table1 这个内容 URI,它所对应的 MIME类型就可以写成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1
对于 content://com.example.app.provider/table1/1 这个内容 URI,它所对应的 MIME 类型就可以写成:
vnd.android.cursor.item/vnd. com.example.app.provider.table1
可以看到, 几乎每一个方法都会带有 Uri这个参数, 这个参数也正是调用 ContentResolver
的增删改查方法时传递过来的。一个标准的内容 URI写法是这样的:
content://com.example.app.provider/table1
除此之外,我们还可以在这个内容 URI的后面加上一个 id
content://com.example.app.provider/table1/1
表示调用方期望访问的是 com.example.app这个应用的 table1表中 id 为 1的数据。
我们可以使用通配符的方式来分别匹
配这两种格式的内容 URI,规则如下。
1. *:表示匹配任意长度的任意字符
2. #:表示匹配任意长度的数字
所以,一个能够匹配任意表的内容 URI格式就可以写成:
content://com.example.app.provider/*
而一个能够匹配 table1表中任意一行数据的内容 URI格式就可以写成:
content://com.example.app.provider/table1/#
再借助UriMatcher这个类就可以轻松地实现匹配内容URI的功能。 UriMatcher中提供了一个 addURI()方法,这个方法接收三个参数,可以分别把权限、路径和一个自定义代码传进去。这样,当调用 UriMatcher 的 match()方法时,就可以将一个 Uri 对象传入,返回值是某个能够匹配这个 Uri 对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了
public class MyProvider extends ContentProvider {
public static final int TABLE1_DIR = 0;
public static final int TABLE1_ITEM = 1;
public static final int TABLE2_DIR = 2;
public static final int TABLE2_ITEM = 3;
private static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
uriMatcher.addURI("com.example.app.provider ", "table1/#", TABLE1_ITEM);
uriMatcher.addURI("com.example.app.provider ", "table2", TABLE2_ITEM);
uriMatcher.addURI("com.example.app.provider ", "table2/#", TABLE2_ITEM);
}
.....
再利用uriMatcher.match()的返回值判断期望访问的是哪张表中的数据。
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
// 查询table1表中的所有数据
//uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
break;
case TABLE1_ITEM:
// 查询table1表中的单条数据
break;
case TABLE2_DIR:
// 查询table2表中的所有数据
break;
case TABLE2_ITEM:
// 查询table2表中的单条数据
break;
default:
break;
}
……
}
最后别忘了给ContentProvider注册:
<provider
android:name="com.example.sixthchapter.DatabaseProvider"
android:authorities="com.example.sixthchapter.provider"
android:exported="true" >
</provider>
接下来就可以在别的程序里面通过getContentResolver()获得实例就可以操作数据了。
getContentResolver().insert();
getContentResolver().delete();
getContentResolver().updata();
getContentResolver().query();
public void onClick(View v) {
Uri uri = Uri.parse("content://com.example.sixthchapter.provider/book");
switch (v.getId()) {
case R.id.insent:
ContentValues values = new ContentValues();
values.put("name", "diyihangdaima");
values.put("author", "guolin");
values.put("price", "68.55");
values.put("pages", "486");
Uri newUri = getContentResolver().insert(uri, values);
values.clear();
break;
case R.id.query:
Cursor cursor = getContentResolver().query(uri, null, null, null,
null);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor
.getColumnIndex("name"));
String author = cursor.getString(cursor
.getColumnIndex("author"));
int pages=cursor.getInt(cursor
.getColumnIndex("pages"));
double price=cursor.getDouble(cursor
.getColumnIndex("price"));
Log.d("MainActivity", "name=" + name);
Log.d("MainActivity", "author=" + author);
Log.d("MainActivity", "pages=" + pages);
Log.d("MainActivity", "price=" + price);
}
cursor.close();
}
break;
default:
break;
}
}
logcat: