【Android】【笔记】《Android 入门经典》part 11 ContentProvider 数据共享

本文为个人读书笔记,大部分为书中内容摘要。仅供记录和分享学习中遇到的需要留意的问题,如有相关版权问题请及时通知作者。
 
ContentProvider保存和获取数据并使其对所有应用程序可见。这是不同应用程序间共享数据的唯一方式。在Android中,没有提供所有应用共同访问的公共存储区域。

Content Provider概述
     Content Provider内部如何保存数据由其设计者决定。但是所有的Content Provider都实现一组通用的方法用来提供数据的增、删、改、查功能。
     客户端通常不会直接使用这些方法,大多数是通过ContentResolver对象实现对Content Provider的操作。可以通过调用Activity或其他应用程序组件的实现类中的getContentResolver()方法来获得Content Provider。
          eg:ContentResolver cr=getContentReolver();
     使用ContentResolver提供的方法可以获得Content Provider中任何感兴趣的数据。
     当开始查询时,Android系统确认查询的目标Content Provider并确保它正在运行。系统会初始化所有Content Provider类的对象,开发人员不必完成此类操作。实际上,开发人员根本不会直接使用ContentProvider类的对象。通常每个类型的ContentProvider仅有一个单独的实例,但是该实例能与位于不同应用程序和进程的多个ContentResolver类对象通信。不同进程之间的通信由ContentProvider类和ContentResolver类处理。

数据模型
     ContentProvider使用基于数据库模型的简单表格来提供其中的数据,每行代表一条记录,没列代表特定类型和含义的数据。
     每条记录包含一个数值型的 _ID字段,用于在表格中唯一标识该记录。
     查询返回一个Cursor对象,它能遍历各行各列来读取各个字段的值。对于各个类型的数据,它都提供了专用的方法。因此,为了读取字段的数据,开发人员必须知道当前字段包含的数据类型。

URI的用法
     每个Content Provider提供公共的URI(使用URI类包装)来唯一标识其数据集。管理多个数据集(表格)的Content Provider为每个都提供了单独的URI。所有为provider提供的URI都已“content://“作为前缀,“content://“模式表示数据由Content Provider来管理。
     如果自定义ContentProvider,则应该为其URI也定义一个常量来简化客户端代码。Android为当前平台提供的ContentProvider定义了CONTENT_URI常量。匹配电话号码到联系人表格的URI:android.provider.Contacts.Phones.CONTENT_URI。匹配保存联系人照片表格的URI:android.provider.Contacts.Photos.CONTENT_URI
     URI常量用于所有与ContentProvider的交互中。每个ContentResolver方法使用URI作为其第一个参数。它标识ContentResolver应该使用哪个provider及其中的哪个表格。

          content://     com.xx.xxx     /dba     /001
          A                     B                    C          D
     A :标准前缀,标识该数据由ContentProvider管理。永远不用修改。
     B:URI的authority部分,标识该ContentProvider。对于第三方应用,该部分应该是完整的类名来保证唯一性。在<provider>元素的authorities属性中声明authority。
     C:ContentProvider路径部分,用于木额定哪类数据被请求。如果ContentProvider仅提供一种数据类型,这部分可以没有。如果provider提供几种类型,把偶哦子类型,这部分可以由几部分组成。
     D:被请求的特定记录的ID值。这是被请求记录的_ID值。如果请求不仅限于单条记录,该部分及其前面的斜线应该删除


ContentProvider的几种操作
     Android系统为常用数据类型提供了很多预定义的Content Provider,大都位于android.provider包中。开发人员可以查询这些provider以获得其中包含的信息。
     Android系统提供的常见ContentProvider
ContentProvider 功能
Browser 读取或修改书签、浏览历史或网络搜索
CallLog 查看或更新通话记录
Contacts 获取、修改或保存联系人信息
LiveFolders 由ContentProvider提供内容的特定文件夹
MediaStore 访问声音、视频、图片
Setting 馋看和获取蓝牙设置、铃声和其他设备偏好
SearchRecentSuggestion 能被配置以使用查找意见provider操作
SyncStateContract 用于使用数据组账号关联数据的ContentProvider约束。希望使用标准方式保存数据的provider可以使用
UserDictionary 可预测文本输入。应用程序和输入法能增加数据到该字典。单词能关联频率信息和本地化信息

查询数据
     开发人员需要3条信息查询ContentProvider中的数据
     1、标识该Content Provider的URI
     2、需要查询的数据字段名称
     3、字段中数据的类型
     如果查询特定的记录,还需要提供该记录的ID
     查询ContentProvider中的数据,需要使用ContentResolver.query()或Activity.messageQuery()方法。这两个方法使用相同的参数,都返回Cursor对象。然而,managedQuery()方法导致Activity管理Cursor的生命周期。托管的Cursor处理所有的细节,例如当Activity暂停时卸载自身,当Activity重启时加载自身。调用Activity.startManagingCursor()方法可以让Activity管理未托管的Cursor对象。
     query()和managedQuery()方法的第一个参数是provider的URI,即标识特定ContentProvider和数据集的CONTENT_URI常量。
     为了限制仅返回一条记录,可以在URI结尾增加该记录的_ID值,即将匹配ID值的字符串作为URI路径部分的结尾片段。
     ContentUris.withAppendedID()和URI.withAppendenPath()等辅助方法,可以将ID增加到URI。这两个方法都是静态方法并返回一个增加了ID的Uri对象。
     query()和managedQuery()方法其他参数用来更加细致地限制查询结果:
     1、应返回的数据列名称。null表示返回全部。否则仅返回列出的列。全部预定义Content Provider为其列都定义了常量。例如android.provider.Contacts.Phone类定义了_ID、NUMBER、BUMBER_KEY、NAME。
     2、决定哪些行被返回的过滤器,格式类似SQL的WHERE语句。null值表示返回全部行(除非URI限制查询结果限制为单行记录)
     3、选择参数
     4、返回记录的排序器,格式类似SQL的ORDER BY语句。null表示已默认顺序返回记录,可能是无序的。
     5、查询返回一组零条或多条数据库记录。列明、默认顺序和数据类型对每个Content Provider都是特别的。但是每个provider都有一个_ID列,它为每条记录保存唯一的数值ID。每个provider也能使用_COUNT包干返回结果中记录的行数,该值在各行都是相同的。
     6、获得数据使用Cursor对象处理,它能向前或者向后遍历整个结果集。开发人员可以使用它来读取数据。增加、修改、删除数据则必须使用ContentResolver对象

增加记录
     首先在ContentValues对象中建立键值对映射,这里每个键匹配ContentProvider中的列名,每个值是该列中希望增加的值。然后调用CotentResolver.insert()方法并传递给它provider的URI参数和ContentValues映射。该方法返回新记录的完整URI,即增加了新纪录ID的URI。开发人员可以使用该URI来查询并获取该记录的Cursor,以便修改该记录。

增加新值
     增加记录到Contacts数据库的最佳方式是增加保存新数据的表名到代表记录的URI,然后使用组装好的URI来增加新数据。每个Contacts表格以CONTENT_DIRECTORY常量的方式提供名称作为该用途。
     开发人员可以调用使用byte数组作为参数的ContentValues.put()方法向表格中增加少量二进制数据。适用于小图标的图片、短音频片段等。如果需要增加大量二进制数据,保存代表数据的content:URI到表格,然后使用文件URI调用ContentResolver.openOutputStream()方法。这导致ContentProvider保存数据到文件并在记录的隐藏字段保存文件路径。

批量更新数据
     使用ContentResolver.update()方法并提供需要修改的列名和值。

删除记录
     单条记录:调用ContentResolver.delete()方法并提供特定行的URI
     多条记录:调用ContentResolver.delete()方法并提供删除记录类型的URI和一个SQL WHERE语句。
【13.6】




根据需要Content Provider
     开发人员共享自己的数据,有两个选择:
     1、创建自定义的Content Provider(一个ContentProvider类的子类);
     2、如果有预定义的provider,管理相同的数据类型并且有写入权限,则可以向其中增加数据。

     如果自定义Content Provider,则开发人员需要完成以下操作:
     1、建立数据存储系统。大多数Content Provider使用Android文件存储方法或者SQLite数据库保存数据,但是开发人员可以使用任何方式存储。Android提供了SQLiteOpenHelper类帮助创建数据库,SQLiteDatabase类管理数据库。
     2、继承ContentProvider类来提供数据访问方式。
     3、在应用程序的AndroidManifest文件中声明Content Provider。

继承ContentProvider类
     开发人员定义ContentProvider类的子类以便使用ContentResolver和Cursor类来共享数据。原则上,需要实现ContentProvider类定义的以下6个抽象方法:
     public boolean onCreate()
     public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder)
     public Uri insert(Uri uri,ContentValues values)
     public int update(Uri uri,ContentValues values,String selection,String[])
     public int delete(Uri uri,String selection,String[] selectionArgs)
     public String geType(Uri uri)

方法 说明
onCreate() 初始化provider
query() 返回数据给调用者
insert() 插入新数据到Cotent Provider
update() 更新Content Provider中已经存在的数据
delete() 从Content Provider中删除数据
getType() 返回Content Provider数据的MIME类型

     query()方法必须返回Cursor对象,用于遍历查询结果。Cursor自身是一个接口,但是Android提供了一些该接口的实现类
     由于这些ContentProvider方法能被位于不同进程和线程的不同ContentResolver对象调用,它们必须以线程安全的方式实现。
     此外,开发人员如果想调用ContentResolver.notifyChange()方法以便在数据修改时通知监听器。
     除了定义子类自身,还应采取一些其他措施以便简化客户端工作并让类更加易用:
     1、定义public static final Uri CONTENT_URI变量。该字符串表示自定义的Content Provider处理的完整的content:URI。开发人员必须为该值定义唯一的字符串。最佳的解决方式是使用Content Provider的完整类名。
     如果provider包含子表,也应该为各个子表定义URI。这些URI应该有相同的authority(因为它标识Cotent Provider)然后使用路径进行区分。
     2、定义Content Provider将返回给客户端的列名。如果开发人员使用底层数据库,这些列名通常与SQL数据库列名相同。同样定义public static String常量,客户端用它们来指定查询中的列和其他指令。确保包含为“_ID”的整数列用来作为记录的ID值。无论记录中其他字段是否唯一,开发人员都应该包含该字段。如果打算使用SQLite数据库,_ID字段应该是:    INTEGER PRIMARY KEY AUTOINCREMENT类型
     3、仔细注释每列的数据类型,客户端需要使用这些信息来读取数据。
     4、如果开发人员正在处理新数据类型,则必须定义新的MIME类型以便在ContentProvider.getType()方法实现中返回。
     5、如果开发人员提供的byte数据太大而不能放到表格中,提供给客户端的字段应该包含content:URI字符串。

声明Content Provider
     在应用程序的AndroidManifest.xml文件中定义<provider>元素。没有在配置文件中声明的Content Provider对于Android系统不可见。
     name属性的值是ContentProvider类的子类的完整名称。authorities属性是provider定义的content:URI中authority部分。authorities属性删除了content:URI中的路径部分。
     其他<provider>属性能设置读写数据的权限,提供显示给用户的图表或文本,启用或禁用provider等。如果数据不需要在多个运行着的ContentProvider间同步,则设置multiprocess为true。这允许在各个客户端进程创建一个provider实例,从而避免执行IPC。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值