Android之Content Providers

Content Providersandroid

  Content Providers存储和取得数据,以及让它对全部应用程序可见。这是唯一的跨应用程序共享数据的方法;没有一个全部Android包都能访问的公共存储区域。数据库

  Android整理了一大堆content provider给公共数据类型(音频、视频、图像、联系人信息等待)。你能看见他们中的一些在android.provider包中。你能查询 providers拥有的数据(虽然,有一些,你必须获取合适的权限来读取数据)。数组

  若是你但愿作你本身的数公共数据,你有两个选项:你能够建立你本身的content provider(一个ContentProvider子类)或你能够添加数据到一个已存在的provider--若是有一个控制一样的数据类型的话而且你拥有写的权限。ide

Content Provider Basicsspa

  一个content provider怎样实际存储它的数据由设计者决定。但全部的content provider实现一个公共的接口来查询和取得结果--一样的对添加、修改、删除数据。设计

  这是一个客户间接使用的接口,通常经过ContentResolver对象。你获取一个ContentResolver经过getContentResolver()从activity的实现或其它组件:orm

  

  你能够而后使用ContentResolver的方法来和你感兴趣的任何content provider交互。视频

  当一个查询被初始化,android系统标识被找准的content provider,保证它在运行。系统立马示例全部的ContentProvider对象;你永远不须要本身来作。实际上,你永远不会直接处理 ContentProvider。典型的,每一个ContentProvider只有一个实例。但它能够和多个ContentResolver对象交互在不 同的应用程序和不一样的进程 。进程间交互被ContentResolver和ContentProvider操做。对象

The data model排序

  Content providers暴露他们的数据做为简单的表在基于一个数据库模型,每行是一条记录,每一列是特定类型的数据。例如,关于人的信息和他们的手机能够暴露以下:

  每一条记录包含一个数字_ID域用来唯一标识记录在表中。IDs能够被用来匹配记录在相关表中--例如,为了找到一我的的电话号码在一个表以及在另外一个表中的图。

  查询返回一个Cursor对象,能够移动从记录到记录而且列到列来读取每一个域的内容。它有特殊的方法来读取每一个类型的数据。因此,为了读一个域,你必须知道哪一种类型的数据这个域包含。

URIs

  每个content provider暴露一个公共的URI(Uri对象),用来识别数据集。一个content provider控制多个数据集(多个数据表)为每一个暴露一个URI。全部的URIs以"content://"开始。"content:"方案标识数据 被content provider控制。

  若是你定义一个content provider,定义一个常量为它的URI是个好主意,为了简化客户端代码而且让之后升级更干净。Android定义CONTENT_URI常量为全部 的平台providers。例如,一个表的URI匹配某我的的电话而且这个表的URI拥有这我的的图片(都被联系人content provider控制):

  

  URI常量被用于content provider的交互。每一个ContentResolver方法以URI做为第一个参数。它标致着哪一个一providerContentresolver须要去交流而且哪个表须要被指向。

Querying a Content Provider

  你须要三种信息来查询一个content provider:

  一、标识provider的URI。

  二、你但愿接收的域名。

  三、这个域的数据类型。

  若是你查询某一个记录,你也须要那条记录的ID。

Making the query

  为了查询一个content provider,你可使用ContentResolver.query()方法或Activity.managedQuery()方法。两个方法使用 相同的参数,两个都返回Cursor对象。但是,managedQuery()引发activity来管理 Cursor的生命周期。一个被管理的Cursor操做全部的细节,例如卸载它本身当activity中止,查询它本身当activity重启。你能够要 求一个Activity去管理一个未被管理的Cursor对象为你,经过Activity.startManagingCursor()。

  第一个给query()或managedQuery()的参数是provider的URI--自助CONTENT_URI常量标识一个特定的ContentProvider和数据集。

  为了限制一个查询只能一条记录,你能够添加_ID值给给那个URI--也就是说,放一直匹配的字符串到URI的最后的部分。例如,若是ID是23,那么 URI就会是:

  

  有一些帮助方法,特别是ContentUris.withAppendedId()和Uri.withAppendedPath(),使得添加 一个ID到URI很容易。两个静态方法都返回一个添加了ID的Uri对象。因此,例如,若是你在寻找23号记录在联系人数据库中,你能够构造一个查询像下 面这样:

  

  其它参数限制query()和managedQuery()方法到更细节。他们是:

  一、返回的数据列的名字。NULL值返回全部列。不然,只有被列出名字的值才会返回。全部和平台一块儿的content providers定义常量为他们本身列。例如,android.provider.Contacts.Phones类定义 常量为列名在phone表中就像以前陈述的&mdash _ID、NUMBER、NUMBER_KEY、NAME等等。

  二、一个跟行有关的过滤器,以SQL WHRER每每名(不包含WHERE itself)。一个NULL值返回全部行(除非URI限制单选查询)。

  三、选择参数。

  四、一个排序的行被返回,格式化像SQL ORDER从句(不包括ORDER BY itself)。一个NULL值返回原始记录顺序,也就是没有排序。

   让咱们看一个查询示例,取得联系人名字和他们电话号码的列表:

  这个查询从联系人content provider的人员表中取得数据。它取得名字,电话号码,和唯一的记录ID。它也报告记录的数量做为被每条记录的_COUNT返回的。

  列名常量被定义在不一样的接口--_ID和_COUNT在BaseColumns,NAME在PeopleColumns,以及NUMBER在phoneColumns。Contacts.People类实现每一个接口。

What a query returns

  一个查询返回一系列的零或更多数据库记录。列表、默认序、数据类型对每一个content provider来讲都很特别。但每个provider 有一个_ID列。每一个provider也能将记录数返回在_COUNT列中;它的值和全部的行同样。

  下面是一个例子,展示以前的结果:

  

  取得的数据被暴露给一个Cursor对象能够向后或向前穿越结果集。你可使用这个对象只读数据。添加、修改、删除数据,你必须使用一个ContentResolver对象。

Reading retrieved data

  经过查询得到的Cursor提供访问结果记录的功能。若是你已经查询一个特定记录经过ID,这个集合将包含只有一个值。不然,它能够包含多个 值。(若是没有匹配,它为空)你能够读取数据从指定域在记录中,但你必须知道域的数据类型,由于Cursor对象有一个单独的方法来读各类类型的数据-- 例如getString(),getInt()和getFloat()。(但是,对大多数类型,若是你调用 读取字符串的方法,Cursor对象将给你数据的字符串表示。)Cursor让你请求表列名用索引号,或用列名获取索引号。

  下面的版本陈述读取名字和电话号码从以前的查询:

  

  若是一个查询能返回二进制数据,例如图形或声音,数据 能够直接进入表或数据的表头多是一个字符串“content:URI”,你能使用来获取数据。通常,比较小的数据(20-50K或更小)常常被直接插入 表中并表能够被Cursor.getBlob()读取。它返回一个二进制数组。

  若是表入口是“content:URI”,你应该永远不尝试打开和读取文件直接(其中一点是,权限会致使失败)。相反,你应该调用ContentResolver.openInputStream()来获取一个InputStream对象,你能够用来读取数据。

Modifying Data

  被content provider保存的数据能够被修改:

  一、添加一条新记录。

  二、添加新值到当前的记录。

  三、批量更新当前记录。

  四、删除记录。

  全部的数据修改都经过ContentResolver完成。一些content provider要求更严格的权限写数据。若是你没有权限写入一个content provider,ContentResolver会失败。

Adding records

  添加一条新记录给一个content provider,首先创建键-值对在ContentValues对象,每一个key匹配列名在content provider,而且值是那个记录的那个列指望的值。而后调用ContentResolver.insert()而且传递它provider的URI和 ContentValues 地图。这个方法返回完成的新记录的URI--也就是,provider的新记录添加了ID的URI。你可使用这个URI来查询和得到Cursor关于这 条新记录的,而且进一步修改数据。下面是一个例子:

  

Adding new values

  一旦记录创建,你能够添加新信息为它或修改已存在的信息。例如 ,下一步在上例中将添加联系人信息--像电话号码或IM或e-mail地址--给新的入口。

  最好的方式添加一条记录在联系人数据库是添加表的名字在URI后面,而后使用这个改动的URI来添加数据值。每一个联系表导出一个名字为这个目录做为CONTENT_DIRECTORY常量。下面的代码继续以前的示例经过添加一个电话号码和邮件地址给新记录:

  

  你能够放置小量二进制数据到表中经过调用ContentValue.put()。它对像小图标或短音频起做用,例如。但是,若是你有一大量二进 制数据来添加,例如一个图片或一首完整歌曲,为数据放置"content:URI"在表中而且调用 ContentResolver.openOutputStream()用文件的URI。(这引发content provider存在数据在一个文件,而后记录文件地址在一个隐藏域。)

  在这点上,MediaStore content provider,这个主要的分发图像、音频、视频的provider,利用一个特别的协议:一样的使用query()和managedQuery()的 URI来获取meta-information关于二进制数据(例如,图像的标题或拍摄的日期)和openInputStream一块儿使用来获取它自身的 数据。相似的,和insert()使用的URI放置meta-information给一个MediaStore和openOutputStream的记 录来旋转二进制数据那里。下面的代码版本陈述了这个协议。

  

Batch updating records

  为了气量更新一组记录(例如,为了改变“NY”成“New York”在全部的域),调用ContentResolver.update()方法用列和值来改变。

Deleting a record

  为了删除单条记录,调用 ContentResolver.delete()用URI和指定的行。

  为了删除多条记录,调用 ContentResolver.delete()用记录类型的URI和来删除(例如,android.provider.Contacts.Peopple.CONTENT_URI)而且一个SQL WHERE从句有写哪行被删除。(警告:保证包含一个有效的WHERE若是你在删除通常类型,不然你将有删除比你但愿的更多的数据)。

相关文章
相关标签/搜索