1.前言
内容提供器(Content Provider)作为Android四大组件之一,它主要用在不同的应用程序间实现数据共享的功能。提供了一整套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问的数据的安全性。就目前来看,使用内容提供器是Android实现跨程序共享数据的标准方式。
内容提供器相比较Sharedpreferences和文件存储,可以实现只对一部分数据共享(前者实现的是全局可读写模式)。
2.内容提供器
内容提供器的用法分为两种:
1.使用现有的内容提供器来读取和操作相应程序中的数据
2.创建自己的内容提供器给我们的程序的数据提供外部访问接口。
下面依次介绍两种用法。
2.1 第一种用法(使用现有的内容提供器)
电话簿、短信、媒体库等都提供了一个外部的访问接口,可以供其他应用程序对数据进行访问。
2.1.1 Content Provider的基本使用
访问内容提供器中共享的数据需要借助类ContentResolver,可以通过Context中的getContentResolver()方法获取到该类的实例。ContentResolver中提供了一系列的方法用于对数据进行CRUD操作:
insert(Uri,url,ContentValues values)用于添加数据,
update(Uri url , ContentValues values ,String where , String[] selectionArgs)用于更新数据,
delete(Uri url , String where ,String[] selectionArgs)方法用于删除数据,
query(Uri uri , String[] projection ,String selection,String[] selectionArgs,String sortOrder)方法用于查询数据。
Content Provider使用Uri来进行CRUD操作,称为内容URI。内容URI给内容提供器中的数据建立了唯一标识符,由两部分组成,权限(authority)和路径(path)。权限是用于对不同的应用程序做区分的,为避免冲突,一般都采用程序包名的方式进行命名。路径则是用于对同一应用程序中不同的表做区分的,通常都会添加到权限的后面。比如程序的数据库里存在两张表,table1和table2,这时就可以将路径分别命名为/table1和/table2,然后将权限和路径进行组合,内容URI就变成了com.example.app.provider/table1和com.example.app.provider/table2。但是现在我们很难辨认出这两个字符串就是两个内容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对象就可以去查询table1表中的数据了。示例代码如下:
使用Cursor对象来进行查询
Cursor cursor = getContentResolver().query(uri,projection,selection,selectionArgs,sortOrder);
参数的含义:
uri:指定查询某个应用程序下的某一张表
projection:指定查询的列名
selection:指定where的约束条件
selectionArgs:为where中的占位符提供具体的值
orderBy:指定查询结果的排序方式
查询完成后返回的仍旧是一个Cursor对象,这时就可以将数据从Cursor对象中逐个取出来。代码如下:
if(cursor != null){
while(cursor.moveToNext()){
String column1 = cursor.getString(cursor.getColumnIndex("column1"));
int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
}
cursor.close();
}
- 添加
代码如下:
ContentValue values = new ContentValue();
values.put("column1","text");
values.put("column2",1);
getContentResolver.insert(uri,values);
- 更新
把之前添加的column1中的值清空,代码如下:
ContentValues values = new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1 = ? and column2 = ?",new String[] {"text","1"});
- 删除
getContentResolver().delete(uri,"column2 = ?",new String[]{"1"});
基本的操作就是这样。
2.2 第二种用法 定义自己的Content Provider
定义自己的内容提供器首先需要子类去继承ContentProvider并重写父类中的六个方法:onCreate、query、insert、update、delete、getType。
public class MyContentprovider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
内容Uri的格式主要包含有两种:①以路径结尾表示访问该表中的所有数据(列如,content://com.example.app.provider/table1);②以id结尾表示期望访问该表中拥有相应id的数据(列如,content://com.example.app.provider/table1/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对象所对应的自定义代码,根据这个自定义代码,判断出调用方期望访问的哪张表中的数据了。
还有一个地方要介绍就是我们在重写六个方法时,有一个方法时getType()。该方法是所有的内容提供器都必须提供的一个方法,用于获取Uri对象所对应的MIME类型。一个内容URI所对应的MIME字符串主要有三个部分组成,Android规定三个部分格式如下:
(1)必须vnd开头
(2)如果内容URI以路径结尾,则后接android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/。
(3)最后接上vnd.<authority>.<path>。