内容提供者-Content Provider
Content providers管理对结构化数据集的使用.它们封装数据,并提供了数据安全的机制.Content providers是从一个进程连接另一个进程中的数据的标准接口.
当你想使用一个content provider中的数据,你需在你的应用的Context 中使用ContentResolver对象作为客户端与provider 进行通讯.ContentResolver对象与provider对象通讯,provider是实现ContentProvider的类.Provider对象接收客户端发来的请求,执行请求的动作,返回结果.
如果你不想把你的数据共享给其它应用,你不需开发你自己的provider.然而,你需要自己的provider来在你的应用中提供自定义搜索建议.如果你需要从你的应用中考贝复杂的数据或文件粘贴到其它应用中,你也需要提供自己的provider.
Android自己包含了管理音频,视频,图像,个人通讯录等数据的content providers.你可以从android.provider 包的参考文档中爪到它们.这些providers 可以被所有的android应用使用,但可能带有一些限制.
Content Provider 基础
一个content provider 管理对*数据仓库的使用.一个provider是一个Android应用的一部分,应用一般提供它自己的UI来操作数据.然而,content providers主要是为了给其它应用使用,其它的应用使用provider客户端对象来操作provider.providers 和provider客户端一起提供了一致的,标准的接口来操作用于进程间通讯的数据并保处数据的安全性.
本节讲解以下基础知识:
· content providers如何工作.
· 从content provider取得数据的API.
· 向content provider插入,更新以及删除数据的API.
· 其它有助于使用providers的API.
概述
一个content provider代表了面向外部应用的数据,这些数据看起来就像关系型数据库中的一个或多个table.一行代表某种数据类型的一个实例,一列代表这个实例的一个属性或字段.
举个例子,Android平台中的一个内建的provider是用户词典,它存储了用户想保存的非标准词的拼写.表1 演示了数据在provider的表中可能看起来的样子:
Table 1: 简单用户词典表
word |
app id |
frequency |
locale |
_ID |
mapreduce |
user1 |
100 |
en_US |
1 |
precompiler |
user14 |
200 |
fr_FR |
2 |
applet |
user2 |
225 |
fr_CA |
3 |
const |
user1 |
255 |
pt_BR |
4 |
int |
user5 |
100 |
en_UK |
5 |
在上表中,每行代表了一个不能在标准字典中找到的词.每一列代表了这个词了一个属性.列头是存储在provider中的列的名字.要引用一行的locale属性,需引用locale 列.对于这个provider,_ID列作为"主键"列,provider会自动管理它.
注:一个provider不是必须具备主键的,并且也不是必须使用_ID 作为主键的列名来引用一行.然而,如果你把一个provider绑定到一个ListView,就必须有一个列名叫做_ID.此需求将在显示查询结果一节中有详细的解释.
操作一个provider
应用使用ContentResolver客户端对象来操作content provider中的数据.此对象具有一些与provider 对象中同名的方法,provider对象指的是某个ContentProvider具体派生类的实例.ContentResolver 的方法们提供了对存储数据的基本的"CRUD" (增删改查)功能.
ContentResolver 对象处于客户端应用的线程中,ContentProvider 对象位于另外的进程并且自动处理进程间通讯. ContentProvider 也代表了数据层与可视层之间的一个抽象层.
注:要使用一个provider,你的应用通常需要在manifest请求一些权限, 这将在Content Provider 权限一节中进行更详细的讲解.
举个例子,要从用户词典Provider中获取取单词和它们的locale列表,你需调用ContentResolver.query().query() 方法会调用用户词典中的ContentProvider.query() 方法.下面的代码演示了ContentResolver.query() 调用:
// 查询用户词典并返回结果
mCursor = getContentResolver().query(
UserDictionary.Words.CONTENT_URI, // 单词表的content URI
mProjection, // 每行要返回的列们
mSelectionClause // Selection的条件
mSelectionArgs, // Selection的条件
mSortOrder); // 返回各行要如何排序
表2展示了query(Uri,projection,selection,selectionArgs,sortOrder) 的参数们如何与一个SQL SELECT语句匹配:
Table 2: Query() 与SQL 查询的对比
query() argument |
SELECT keyword/parameter |
Notes |
|
Uri |
FROM table_name |
Uri 对应provider 中叫做table_name的表. |
|
projection |
col,col,col,... |
projection 是每行要包含的列们 |
|
selection |
WHERE col = value |
selection 指定了一些选择条件 |
|
selectionArgs |
(不能对应.替换selection参数各类似于? 的占位符) |
||
sortOrder |
ORDER BY col,col,... |
sortOrder 指定排序方式 |
Content URIs
content URI 是一个标志provider中的数据的URI.Content URI中包含了整个provider的以符号表示的名字(它的authority) 和指向一个表的名字(一个路径).当你调用一个客户端的方法来操作一个provider中的一个表,指向表的content URI是参数之一.
常量CONTENT_URI 中包含了用户词典table的content URI.ContentResolver 对象分析出URI的authority,并使用它与一个已知provider组成的系统表中的authority进行对比来"解决"provider.ContentResolver之后就会派送查询参数给正确的 provider.
ContentProvider使要长content URI的路径辨别分来选择要操作的表.通常一个provider中要暴露的每个表都具有一个路径.
在上面的例子的代码中,"词典"表的全URI是:
content://user_dictionary/words
user_dictionary部分是provider的 authority,words部分是表的路径.字符串 content:// (the scheme) 总是要存在,它表示引用一个content URI.
很多provider允许你通过在URI的末尾增加一个ID来操作表中一个单独的行.例如,要从用户词典中获取_ID是4的一行,你可要行使用这样的content URI:
Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
当你要获取多行然后更新或删除其中一时,你经常要使用的是id值.
注:Uri和Uri.Builder类包含由字符串构建格式正确的Uri对象的简便的方法们.ContentUris 包含向一个URI添加id值的简便方法们.上面的小代码片段就是使用了withAppendedId() 来向UserDictionary content URI添加id.