ContentProvider是在应用程序间共享数据的一种接口机制,它使其他的应用程序保存或读取此ContentProvider的各种数据类型。
ContentProvider提供了更为高级的数据共享方法,应用程序可以指定需要共享的数据,而其他应用程序则可以在不知数据来源、路径的情况下,提供了查询、添加、删除和更新共享数据等操作的接口。许多Android系统的内置数据也通过ContentProvider提供给用户使用,如通讯录、音视频文件和图像文件等。
ContentProvider的数据模式类似于数据库的数据表,每行是一条记录,每列具有相同的数据类型。每条记录都包含一个long型的字段_ID,用来唯一标识每条记录。ContentProvider可以提供多个数据集,调用者使用URI对不同的数据集的数据进行操作。
ContentProvider数据模型如表7-10所示。
表7-10 ContentProvider数据模型
_ID |
NAME |
AGE |
HEIGHT |
1 |
Tom |
21 |
1.81 |
2 |
Jim |
22 |
1.78 |
ContentProvider完全屏蔽了数据提供组件的数据存储方法。在使用者看来,数据提供者通过ContentProvider提供了一组标准的数据操作接口,却无法得知数据提供者的数据存储方法。数据提供者可以使用SQLite数据库存储数据,也可以通过文件系统或SharedPreferences存储数据,甚至是使用网络存储的方法,这些内容对数据使用者都是不可见的。同时也正是因为屏蔽数据的存储方法,很大程度上简化了ContentProvider的使用难度,使用者只要调用ContentProvider提供的接口方法,就可完成所有的数据操作。
图7-9显示了ContentProvider的调用关系。

图7-9 ContentProvider的调用关系图
首先,在创建ContentProvider时,需要先实现底层的存储功能,可以是数据库、文件系统或是网络存储等,然后在继承ContentProvider的类中实现基本数据操作的接口方法,包括添加、删除、查找和更新等功能。接口主要有以下几个。
□ query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder):通过Uri 进行查询,返回一个Cursor。
□ insert(Uri url, ContentValues values):将一组数据插入Uri 指定的地方。
□ update(Uri uri, ContentValues values, String where, String[] selectionArgs):更新Uri 指定位置的数据。
□ delete(Uri url, String where, String[] selectionArgs):删除指定Uri 并且符合一定条件的数据。
其次,我们看出调用者不能够直接调用ContentProvider的接口方法,而需要使用ContentResolver对象,通过Uri间接调用ContentProvider。那么什么是ContentResolver对象呢?
ContentResolver 接口是外界的程序访问ContentProvider 提供的数据桥梁, ContentResolver 提供的接口和ContentProvider 中需要实现的接口对应,主要有以下几个。
□ query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder):通过Uri 进行查询,返回一个Cursor。
□ insert(Uri url, ContentValues values):将一组数据插入Uri 指定的地方。
□ update(Uri uri, ContentValues values, String where, String[] selectionArgs):更新Uri 指定位置的数据。
□ delete(Uri url, String where, String[] selectionArgs):删除指定Uri 并且符合一定条件的数据。
程序开发人员在Activity 当中通过getContentResolver()可以得到当前应用的ContentResolver 对象,然后使用该ContentResolver对象与ContentProvider进行交互,而ContentResolver则通过Uri确定需要访问的ContentProvider的数据集。在发起一个请求的过程中,Android首先根据Uri确定处理这个查询的ContentResolver,然后初始化ContentResolver所有需要的资源,这个初始化的工作无须程序开发人员参与,是Android系统完成的。一般情况下只有一个ContentProvider对象,但却可以同时与多个ContentResolver在不同的应用程序和不同的进程中进行交互。
Uri是通用资源标志符(Uniform Resource Identifier),用来定位任何远程或本地的可用资源。在ContentProvider 和ContentResolver 当中用到的Uri语法结构如代码清单7-46所示。
代码清单7-46 ContentProvider使用的Uri语法结构
content://<authority>/<data_path>/<id>
content://是通用前缀,表示该Uri用于ContentProvider定位资源,无须修改;<authority>是授权者名称,用来确定具体由哪一个ContentProvider提供资源。因此,一般<authority>都由类的包名+类名小写全称组成,以保证唯一性。
<data_path>是数据路径,用来确定请求的是哪个数据集。如果ContentProvider仅提供一个数据集,数据路径则是可以省略的;如果ContentProvider提供多个数据集,数据路径则必须指明具体是哪一个数据集。数据集的数据路径可以写成多段格式,例如/people/girl和/people/boy。
Uri 可以指定全部数据,也可以是指定某个ID 的数据。这里我们就用到了上述语法结构中的后一个参数:<id>。<id>>是数据编号,用来唯一确定数据集中的一条记录,用来匹配数据集中_ID字段的值,如果没有指定<id>,那么表示返回全部。请求整个people数据集的Uri应写为如代码清单7-47所示的代码。
代码清单7-47 请求数据的Uri例子
//请求全部的联系人数据的Uri
content://contacts/people/
//请求ID 为1 的联系人的数据的Uri
content://contacts/people/1
//请求整个people数据集的Uri
content://cn.com.farsight.peopleprovider/people
//请求people数据集中第3条数据的Uri
content://cn.com.farsight.peopleprovider/people/3