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>。