安卓四大组件之内容提供者,安卓四大提供者
内容提供者ContentProvider,是Android 的四大组件之一。内容提供者是应用程序之间共享数据的接口。应用程序创建的数据库,默认情况下是私有的,别的应用程序访问不到数据,如果想把数据对外提供,就要用到内容提供。ContentProvider屏蔽了数据存储的细节,内部实现对用户完全透明, 用户只需要关心操作数据的uri就可以了,ContentProvider可以实现不同app之间共享。 Sql也有增删改查的方法,但是sql只能查询本应用下的数据库。 而ContentProvider 还可以去增删改查本地文件/xml文件的读取等。Android 系统将这种机制应用到方方面面,比如:联系人(通讯录应用程序)Provider 专为不同应用程序提供联系人数据;短信(短信应用程序)Provider 专为不同应用程序提供系统短信信息。当应用继承ContentProvider 类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用SharedPreferences 共享数据,需要使用SharedPreferences API 读写数据。而使用ContentProvider 共享数据的好处是统一了数据访问方式。总之,内容提供者管理了对结构化数据最常见的就是数据库中数据的访问,操作内容提供者是不同进程之间以数据库数据形式交互数据的标准方式。
自定义的内容提供者包括内容提供者和访问者两个部分。
内容提供者,拥有自己的数据库,将数据库暴露出来供访问者修改。ContenProvider的编写基本步骤:
1. 写一个类继承 ContentProvider;
2. 重写一系列的方法,包括数据库操作的空实现;
3. 在内容提供者代码内部定义UriMatcher -用于判断uri是否匹配
static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { mUriMatcher.addURI("在清单文件里面定义的authorities", "自定义匹配字符串", 成功返回的标识);
}
4. 在增删改查执行的时候判断uri是否合法,在内容提供者内部实现对数据库的增删改查;
5. 清单文件的下面声明provider,这里需要指定主机名,也就是对外提供的Uri,当访问者在内容解析者中传入同一个uri时,才可以访问到数据库;
<provider
android:name="com.itheima.db.BankDBBackdoor"
android:authorities="自定义主机名" >
</provider>
访问者,存在于另外一个工程中,可以对内提供者的数据库进行操作。
1. 创建内容提供者解析器
ContentResolver resolver = 上下文.getContentResolver();
2. 定义要访问的Uri路径
Uri uri = Uri.parse("content://自定义主机名/自定义匹配字符串") // “content://”是标准写法
3. 利用内容提供者解析器进行增删改查,实现对数据库的操作
内容提供者Uri 的书写模板: content:// 主机名authority/path/id。具体的书写规范如下所示:
1. "content://" 这是个固定写法,用来说明一个ContentProvider 控制这些数据。
2. 主机名或授权Authority:它定义了是哪个ContentProvider 提供这些数据。
3. path:路径,URI 下的某一个Item。
4. ID:通常定义Uri 时使用”#”号占位符代替, 使用时替换成对应的数字。#表示数据id,#代表任意数字,*用来来匹配任意文本
使用内容提供者操作系统短信和操作系统联系人是我们开发中经常遇到的需求,而自定义内容提供者对外提供数据反而使用的场景并不多,除非我们开发的短信或者联系人应用。一个小细节是,由于读取和插入系统短信数据库都涉及到可能侵犯用户隐私,因此创建的工程必须添加相关的权限。下面就分别讲解一下使用内容提供者操作系统数据库和自定义内容提供者。
用内容提供者操作系统短信只需要关注的到系统短信数据库的一张表,最长用的数据有body,date,type,address,各自的含义也较为直观。body表示短信的内容,date表示发送短信或收到短信的时间,type表示是受到短信还是发送短信,address表示收到的短信来自于哪个手机号。读取和插入系统短信数据库需要添加如下权限:
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
使用内容观察者操作系统联系人时需要关注三张张数据表,rawcontact表 ,data表和 mimetype表。其中raw_contacts 表存放的是联系人id 信息,一个联系人就是表中的一行记录。ontact_id在表单里应该是唯一的存在, 所以在插入的时候需要先查询最后一条id是多少,然后在此基础上加一。data 表中存放的是raw_contacts中的每一条id 对应的具体信息,一个联系人可能有电话、邮件、姓名等多条信息,每一条信息在该表中都是一行记录。为了区分不同信息的类型,因此还有一个mimetypes 表,该表存储的是常量数据,不同类型的信息由mimetype_id 来标识。现在很多App 都可以对系统联系人进行操作,这样就可以直接将号码添加到系统联系人中,可以关联/备份/恢复系统联系人。读取联系人信息的基本步骤是,首先查询rawcontact表,获取联系人的contactid,在rawcontact表中并不是每一个contact_id对应一条信息,而是一个contact_id对应多条信息,这样可以存储更多的信息。其次查询根据contact_id查询data表,获取联系人的数据 data1、mimetype,前者存储相关数据,后者存储该数据对应得数据。最后根据mimetype类型确定数据类型。修改联系人的操作是往raw_contacts 表中插入一个id,值为n+1,作为一条新的记录,然后往data1 表中插入具体的数据,其中id 必须为n+1。读取和插入系统联系人数据库需要添加如下权限:
<uses-permission android:readPermission="android.permission.READ_CONTACTS"
<uses-permission android:writePermission="android.permission.WRITE_CONTACTS"
那么怎么才能获取短信和联系人的Uri呢。这时就需要看源码了。打开Android 系统源码,其中TelephonyProvider 就是短信的内容提供者文件。打开TelephonyProvider 下的src 文件,查看java 文件,其中的SmsProvider.java 即短信息内容提供者逻辑代码。通过查找系统源码,可以确定短信息内容提供者的Uri 应该为:”content://sms”。用同样的方法,可以查到联系人内容提供者的Uri路径。打开Android 源码,查看packages\providers\路径下的文件,其中ContactsProvider 就是联系人的内容提供者。打开ContactsProvider2.java文件,查看此内容提供者的uri 路径。根据源码,确定内容提供者的Uri 信息为:操作raw_contacts 表的Uri:content://com.android.contacts/raw_contacts。操作data 表的Uri:content://com.android.contacts/data。其实,平常写代码时不必要这么复杂,直接把Uri路径拿来就可以用了。另外要注意的是,由于联系人数据库使用了视图,所以操作数据库表时,看到的表字段名称和真实操作的有所不同。比如:data 表在查询的时候没有mimetype_id 字段,取代的是mimetype 字段。