总结Content Provider的使用

转自:http://www.eoeandroid.com/thread-29089-1-1.html

Android中的Content provider机制可支持在多个应用中存储和读取数据。这也是跨应用共享数据的唯一方式。在android系统中,没有一个公共的内存区域,供多个应用共享存储数据。

Android提供了一些主要数据类型的Content provider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些android提供的Content provider。可以获得这些Content provider,查询它们包含的数据,当然前提是已获得适当的读取权限。

如果想公开自己的数据,那么可有两种办法:

  • 创建自己的Content provider,需要继承ContentProvider类;
  • 如果你的数据和已存在的Content provider数据结构一致,可以将数据写到已存在的Content provider中,当然前提是获取写该Content provider的权限。比如把OA中的成员通讯信息加入到系统的联系人Content provider中。

所有Content provider都需要实现相同的接口用于查询Content provider并返回数据,也包括增加、修改和删除数据。

首先需要获得一个ContentResolver的实例,可通过Activity的成员方法getContentResovler()方法:

ContentResolver cr = getContentResolver();

ContentResolver中的方法可实现找到指定的Content provider并获取到Content provider的数据。ContentResolver的查询过程开始,Android系统将确定查询所需的具体Content provider,确认它是否启动并运行它。android系统负责初始化所有的Content provider,不需要用户自己去创建。实际上,content provider的用户都不可能直接访问到content provider实例,只能通过ContentResolver在中间代理。数据模型Content provider展示数据类似一个单个数据库表。其中:

  • 每行有个带唯一值的数字字段,名为_ID,可用于对表中指定记录的定位;
  • Content provider返回的数据结构,是类似JDBC的ResultSet,在android中,是Cursor对象。
URI每个content provider定义一个唯一的公开的URI,用于指定到它的数据集。一个content provider可以包含多个数据集(可以看作多张表),这样,就需要有多个URI与每个数据集对应。这些URI要以这样的格式开头:

content://

表示这个uri指定一个content provider。如果你想创建自己的content provider,最好把自定义的URI设置为类的常量,这样简化别人的调用,并且以后如果更新URI也很容易。android定义了CONTENT_URI常量用于URI,比如:

android.provider.Contacts.Phones.CONTENT_URI 
android.provider.Contacts.Photos.CONTENT_URI

要注意的是上面例子中的Contacts,已经在android 2.0及以上版本不赞成使用。

要想使用一个content provider,需要以下信息:

  • 定义这个content provider的URI
  • 返回结果的字段名称
  • 这些字段的数据类型
如果需要查询content provider数据集的特定记录(行),还需要知道该记录的ID的值。构建查询就是输入URI等参数,其中URI是必须的,其他是可选的,如果系统能找到URI对应的content provider将返回一个Cursor对象。可以通过ContentResolver.query()或者Activity.managedQuery()方法。两者的方法参数完全一样,查询过程和返回值也是相同的。区别是,通过Activity.managedQuery()方法,不但获取到Cursor对象,而且能够管理Cursor对象的生命周期,比如当Activity暂停(pause)的时候,卸载该Cursor对象,当Activity restart的时候重新查询。另外,也可以对一个没有处于Activity管理的Cursor对象做成被Activity管理的,通过调用Activity.startManaginCursor()方法。类似这样:

Cursor cur = managedQuery(myPerson, null, null, null, null);

其中第一个参数myPerson是Uri类型实例。如果需要查询的是指定行的记录,需要用_ID值,比如ID值为23,URI将是类似:

content://. . . ./23

android提供了方便的方法,让开发者不需要自己拼接上面这样的URI,比如类似:

Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);

或者

Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");

二者的区别是一个接收整数类型的ID值,一个接收字符串类型。其他几个参数:

  • names,可以为null,表示取数据集的全部列,或者声明一个String[]数组,数组中存放列名称,比如:People._ID。一般列名都在该Content provider中有常量对应;
  • 针对返回结果的过滤器,格式类似于SQL中的WHERE子句,区别是不带WHERE关键字,如果返回null表示不过滤,比如name=?
  • 前面过滤器的参数,是String数组,是针对前面条件中?占位符的值;
  • 排序参数,类似SQL的ORDER BY字句,不过不需要写ORDER BY部分,比如name desc,如果不排序,可输入null。
返回值是Cursor对象,游标位置在第一条记录之前。下面实例适用于android 2.0及以上版本,从android通讯录中得到姓名字段:

Cursor cursor = getContentResolver().query( 
        ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, 
        null, 
        null);

返回值的内容
_ID _COUNT NAME NUMBER
44 3 Alan Vain 212 555 1234
13 3 Bully Pulpit 425 555 6677
53 3 Rex Cars 201 555 4433

返回值的内容类似上图,不同的content provider会有不同的列和名称,但是会有两个相同的列,上面提到过的一个是_ID,用于唯一标识记录,还有一个_COUNT,用于记录整个结果集的大小,可以看到上面图中的_COUNT的值是相同的。读取返回的数据如果在查询的时候使用到ID,那么返回的数据只有一条记录。在其他情况下,一般会有多条记录。和JDBC的ResultSet类似,需要操作游标遍历结果集,在每行,再通过列名获取到列的值,可以通过getString()、getInt()、getFloat()等方法获取值。比如类似下面:

while (cursor.moveToNext()) { 
    builder 
            .append( 
                    cursor 
                            .getString(cursor 
                                    .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)))
            .append("-"); 
}


和JDBC中不同,没有直接通过列名获取列值的方法,只能先列名获取到列的整型索引值,然后再通过该索引值定位获取列的值。编辑数据可以通过content provider实现以下编辑功能:

  • 增加新的记录;
  • 在已经存在的记录中增加新的值;
  • 批量更新已经存在的多个记录;
  • 删除记录。
所有的编辑功能都是通过ContentResolver的方法实现。一些Content provider对权限要求更严格一些,需要写的权限,如果没有会报错。增加记录要想增加记录到content provider,首先,要在ContentValues对象中设置类似map的键值对,在这里,键的值对应content provider中的列的名字,键值对的值,是对应列希望的类型。然后,调用ContentResolver.insert()方法,传入这个ContentValues对象,和对应Content provider的URI即可。返回值是这个新记录的URI对象。这样你可以通过这个URI获得包含这条记录的Cursor对象。比如:

ContentValues values = new ContentValues();

values.put(People.NAME, "Abraham Lincoln");

Uri uri = getContentResolver().insert(People.CONTENT_URI, values);

在原有记录上增加值如果记录已经存在,可在记录上增加新的值,或者编辑已经存在的值。首先要过去到原来的值对象,然后要清除原有的值,然后像上面增加记录一样即可:

Uri uri=Uri.withAppendedPath(People.CONTENT_URI, "23");

Uri phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);

values.clear(); 
values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE); 
values.put(People.Phones.NUMBER, "1233214567"); 
getContentResolver().insert(phoneUri, values);

批量更新值批量更新一组记录的值,比如NY改名为Eew York。可调用ContenResolver.update()方法。删除记录如果是删除单个记录,调用ContentResolver.delete()方法,URI参数,指定到具体行即可。如果是删除多个记录,调用ContentResolver.delete()方法,URI参数指定Content provider即可,并带一个类似SQL的WHERE子句条件。这里和上面类似,不带WHERE关键字。创建自己的Content provider创建content provider,需要:

  • 设置存储系统。大多数content provider使用文件或者SQLite数据库,不过你可以用任何方式存储数据。android提供SQLiteoOpenHelper帮助开发者创建和管理SQLiteDatabase。
  • 继承ContentProvider,提供对数据的访问。
  • 在manifest文件中声明content provider。
继承ContentProvider类必须定义ContentProvider类的子类,需要实现如下方法:query() 
insert() 
update() 
delete() 
getType() 
onCreate()query()方法,返回值是Cursor实例,用于迭代请求的数据。Cursor是一个接口。android为该接口提供了一些只读的(和JDBC的ResultSet不一样,后者还提供可写入的可选特性)Cursor实现。比如SQLiteCursor,可迭代SQLite数据库中的数据。可以通过SQLiteDatabase类的query()方法获取到该Cursor实例。还有其他的Cursor实现,比如MatrixCursor,用于数据不是存储在数据库的情况下。因为Content provider可能被多个ContentResolver对象在不同的进程和线程中调用,因此实现Content provider必须考虑线程安全问题。作为良好的习惯,在实现编辑数据的代码中,要调用ContentResolver.notifyChange()方法,通知那些监听数据变化的监听器。在实现子类的时候,还有一些步骤可以简化Content provider客户端的使用:定义public static final Uri常量,名称为CONTENT_URI:

public static final Uri CONTENT_URI = 
               Uri.parse("content://com.example.codelab.transportationprovider");

如果有多个表,它们也是使用相同的CONTENT_URI,只是它们的路径部分不同。

image_thumb3.png 

也就是说红色框部分是一致的。定义返回的列名,public static final,列名的值,比如使用SQLite数据库作为存储,对应表的列名。在文档中要写出各个列的数据类型,便于使用者读取。如果需要处理新的MIME数据类型,比如通过Intent的方式,并且带data的mimeType,那么需要在ContentProvider.getType()方法中进行处理。声明Content Provider创建Content Provider后,需要在manifest文件中声明,android系统才能知道它,当其他应用需要调用该Content Provider时才能创建或者调用它。语法类似:

<provider android:name="com.easymorse.cp.MyContentProvider" 
            android:authorities="com.easymorse.cp.mycp"></provider>

android:name要写ContentProvider继承类的全名。android:authorities要写和CONTENT_URI常量的B部分(见上面图)。注意不要把上图C和D部分加到authorities中去。authorities是用来识别ContentProvider的,C和D部分实际上是ContentProvider内部使用的。


content_uri.png







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目 录 I 关于本博客的主题 III 第一章 什么是Android 1 什么是Android - 嵌入式设备编程的历史-第一章(1) 1 开放手机联盟和Android-(2) 2 介绍Android 第一章(3) 2 Android示例 - 第四章(4) 3 Android的几个示例 - 第四章(5) 4 第二章 下载和安装Eclipse总则 5 下载和安装Eclipse总则 - 第二章(1) 5 下载和安装JRE - 第二章(2) 6 下载和安装Eclipse - 第二章(3) 7 第三章 下载和安装Android SDK 8 下载和安装Android SDK - 第三章(1) 8 下载Android SDK - 第三章(2) 9 为Eclipse配置Android Plugin - 第三章(3) 10 第四章 浏览Android SDK 11 浏览Android SDK - 第四章(1) 11 Android SDK是什么 - 第四章(2) 12 Android 文档 - 第四章(3) 12 Android示例 - 第四章(4) 13 Android的几个示例 - 第四章(5) 14 Android工具 - 第四章(6) 14 Android APIs - 第四章(7) 15 应用程序生命周期 - 第四章(8) 16 第五章Android程序:Hello World! 17 Android程序:Hello World! -第五章(1) 17 仔细查看Android创建的文件 - 第五章(2) 19 引用库和目录 - 第五章(3) 20 Hello World!自动产生文件的详解 - 第五章(4) 21 Hellow World! 再来一次 - 第五章(5) 23 Hello World! 使用一个图形 - 第五章(6) 25 Hello World!代码为基的UI-第五章(7) 26 Hello World! XML为基的UI - 第五章(8) 27 第六章 使用命令行工具和Android模拟器 29 使用命令行工具和Android模拟器 - 第六章(1) 29 利用Windows CLI创建一个壳活动 - 第六章(2) 29 运行ActivityCreator.bat - 第六章(3) 30 项目结构 - 第六章(4) 32 在Windows CLI下创建Hello World!活动 - 第六章(5) 36 增加JAVA_HOME 第六章 (6) 36 编译并安装应用程序 第六章(7) 37 如果运行ANT时出错该怎么办? 第六章(8) 37 用adb安装你的应用程序 第六章(9) 40 运行应用程序产生了一个错误怎么办 - 第六章(10) 41 卸载一个较早的活动 - 第六章(11) 41 重新安装并启动应用程序 - 第六章(12) 42 Linux上的Hello World! 第六章(13) 42 在CLI中创建一个图片基础的Hello World! 第六章(14) 44 第七章 使用Intents 和电话拨号盘 44 使用Intents 和电话拨号盘 第七章(1) 44 Intents是什么? 第七章(2) 45 使用拨号盘 第七章(3) 49 从你的活动中打出电话 第七章(4) 51 编辑活动许可 第七章(5) 53 修改AndroidPhoneDialer 第七章(6) 55 执行一个EditText View 第七章(7) 58 试试这个:修改AndoridPhoneDialer项目 第七章(8) 61 第八章 列表,菜单和其它Views 63 列表,菜单和其它Views 第八章(1) 63 修改AndroidManifest.xml文件 第八章(2) 65 使用菜单 第八章(3) 67 为AutoComplete创建一个活动 第八章(4) 71 按钮 第八章(5) 77 CheckBox 第八章(6) 80 EditText 第八章(7) 85 RadioGroup 第八章(8) 89 Spinner 第八章(9) 93 试试这个:修改更多的View属性 第八章(10) 98 第九章 使用手机的GPS功能 98 使用手机的GPS功能 第九章(1) 98 什么是轨迹文件 第九章(2) 101 使用Android位置基础API读取GPS 第九章(3) 102 书写代码来允许活动 第九章(4) 105 传递坐标到Google地图 第九章(5) 107 增加缩放控制 第九章(6) 110 试试这个:在MapView之间转换 第九章(7) 114 第十章 使用Google API的Gtalk 118 使用Google API的GTalk 第十章(1) 118 在Android中执行GTalk 第十章(2) 120 编译并运行GoogleAPI 第十章(3) 126 试试这个:为GoogleAPI活动增加设置特性 第十章(4) 128 第十一章 应用程序:找一个朋友 128 应用程序:找一个朋友 第十一章(1) 128 创建一个SQLite数据库 第十一章(2) 129 创建一个定制的Content Provider 第十一章(3) 130 创建Content Provider 第十一章(4) 132 创建FindAFriend活动 第十一章(5) 141 创建NameEditor活动 第十一章(6) 143 创建LocationEditor活动 第十一章(7) 146 创建FriendsMap活动 第十一章(8) 154 创建FindAFriend活动 第十一章(9) 160 运行FindAFriend活动 第十一章(10) 163 Android SDK 工具参考 第十二章 (完) 164 Android SDK 工具参考 第十二章 (完) 164 Android SDK 1.5 - 包装索引 169
Android Framework核心知识笔记是一本介绍Android Framework核心知识的pdf文档。Android Framework是Android系统的基础,它包含了一系列的类库和API,为开发Android应用程序提供了基本的功能和特性。 这本笔记首先介绍了Android Framework的概述,包括其组成部分和架构。然后详细讲解了Android四大组件(Activity、Service、Broadcast Receiver和Content Provider)的实现原理和使用方法。这些组件是Android应用程序的基本构建模块,理解它们的工作原理对于开发高质量的Android应用程序至关重要。 接着,笔记对Android Framework中的UI设计进行了深入讲解。它介绍了View和ViewGroup的层次结构以及布局管理器的使用方法,帮助开发者实现灵活且具有吸引力的用户界面。此外,它还讨论了Android的绘图机制和动画效果,使开发者能够创建更加生动和吸引人的界面。 另外,笔记还包含了关于Android Framework中的数据存储和访问的内容。它介绍了SharedPreferences、SQLite数据库以及Content Provider等数据持久化的方法,帮助开发者存储和管理应用程序的数据。 此外,笔记还涵盖了与Android Framework相关的其他主题,如网络通信、多媒体处理、传感器和位置服务等。它们帮助开发者实现更多样化和功能强大的应用程序。 总结来说,Android Framework核心知识笔记是一本全面介绍Android Framework的教程,帮助开发者掌握Android应用程序开发的基本技能。对于想要成为Android开发专家的人来说,这是一本不可或缺的参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值