一 为什么需要内容提供者
(1)android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。其他应用可以通过ContentResolver类从该内容提供者中获取或存入数据。
(2)只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处是统一数据访问方式。
(3)ContentProvider实现数据共享。ContentProvider用于保存和获取数据,并使其对所有应用程序可见。这是不同应用程序间共享数据的唯一方式,因为android没有提供所有应用共同访问的公共存储区。
(4)开发人员不会直接使用ContentProvider类的对象,大多数是通过ContentResolver对象实现对ContentProvider的操作。
(5)ContentProvider使用URI来唯一标识其数据集,这里的URI以content://作为前缀,表示该数据由ContentProvider来管理。
二内容提供者实现原理
三 实现内容提供者使用步骤
[1]定义内容提供者 定义一个类继承contentProvider
[2]在清单文件里面配置一下, 定义一些规则 a呀 d
[3] 定义一个urimatcher
[4]写一个静态代码块 添加匹配规则
[5]按照我们添加的匹配规则 暴露想暴露的方法
[6]如果你发现如下log日志 就说明内容提供者写的没有问题
[7]只要是通过内容提供者暴露出来的数据 其他应用访问的方式都是一样的 就是通过内容解析者
四.内容解析器ContextResolver
想要获取到其他应用所暴露出来的数据则必须使用,内容提供者里面的内容解析器ContextResolver
1.首先获取到内容解析器
通过context中的getContentResolver(),来获得一个内容解析器
ContentResolver resolver = getContentResolver();
2.进行数据操作
拿到了内容解析器对象就可以进行相关的ASUQ(增删改查)操作,以读取手机联系人为例。
读取联系人信息只是用到了查询操作,通过query操作去查询
通过 resolver.query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)这个方法查询系统联系人数据库。
参数的含义:
① Uri uri:要查询那个数据库中的那个表
一般是Uri.parse(content://要查询的数据库/表名);
② String[] projection:查询哪一列(表中数据的列名)
③ String selection:查询的条件 such as:”id = ?”
④ String[] selectionArgs:查询条件的值,和查询条件相匹配
当查询条件是”id = ?”时,这里是”id = 5”
如果查询条件是一组数,如”id = ?and name = ?”
则此处应该也是一组数,new String[]{5,”Tom”};
⑤ String sortOrder:排序方式
实现结果:
点击按钮跳转到手机联系人界面,去选择手机联系人
此时可以看到手机联系人,因为系统手机联系人这个应用就已经给我们通过内容提供者提供了一个可以读取数据的接口,我们只需要在代码中实现内容解析器,并且知道联系人的表结构,就可以去读取自己想要的数据
当选择一个条目,那么就会到这这个数据对象回到我们之前的那个界面,将phoneNum读取出来,设置在EditText上面,实现联系人的读取。
//代码操作:(如果联系人多了,读取联系人属于耗时操作,需要放在子线程中执行)
new Thread(){
@Override
public void run() {
//获取广播解析器
ContentResolver resolver = getContentResolver();
//查询系统联系人数据库的raw_contacts表
Cursor cursor = resolver.query(Uri.parse("content://com.android.contacts/raw_contacts"),
new String[]{"contact_id"},null,null,null);
//每次查询都将之前的List清空一下
mList.clear();
//循环查找(cursor中有多少个id,就查询具体内容多少次)
while (cursor.moveToNext()){
//查找到的数据第一个是联系人唯一标示id
String id = cursor.getString(0);
//根据用户唯一id查找data和mimetype合成的视图,找到data1和mimetype字段
Cursor indexCursor = resolver.query(Uri.parse("content://com.android.contacts/data"),
new String[]{"data1", "mimetype"}, "raw_contact_id = ?", new String[]{ id }, null);
//创建一个map集合用来存每次遍历得到的姓名和电话号码的键值对
HashMap<String,String> map = new HashMap<String, String>();
//循环遍历(次数是查询到数据的组数),查找每个联系人的姓名和电话
while (indexCursor.moveToNext()){
//每组数据的具体数据,包括联系人姓名和电话号码
String data = indexCursor.getString(0);
//获取该组中数据的类型
String type = indexCursor.getString(1);
//如果是匹配到"vnd.android.cursor.item/phone_v2",则是电话号码
if (type.equals("vnd.android.cursor.item/phone_v2")){
if (!TextUtils.isEmpty(data)){
//拿到电话号码
map.put("phone",data);
}
}
//如果匹配到"vnd.android.cursor.item/name",则是联系人姓名
if (type.equals("vnd.android.cursor.item/name")){
if (!TextUtils.isEmpty(data)){
//拿到姓名
map.put("name",data);
}
}
}
indexCursor.close();
mList.add(map);
}
cursor.close();
//用消息发送机制发送一个空消息,为了提醒主线程数据获取完毕,
mhandler.sendEmptyMessage(0);
}
}.start();