一、 概述
什么是 Content Provider
Android 的数据存储方式五种中的一种
Shared Preferences
SQLite
网络存储

文件存储


Content Provider ---提供了我们在应用程序之间共享数据的一种机制比如操作
手机里的联系人,增加或者删除
ContentProvider(内容提供者)是 Android 中的四大组件之一。主要用于对外共享数据,
也就是通过 ContentProvider 把应用中的数据共享给其他应用访问,其他应用可以通过
ContentProvider 对指定应用中的数据进行操作
数据库在 Android 当中是私有的,不能将数据库设为 WORLD_READABLE,每个数据库都
只能创建它的包访问。这意味着只有创建这个数据库的应用程序才可访问它。也就是说不能
跨越进程和包的边界,直接访问别的应用程序的数据库。那么如何在应用程序间交换数据

呢? 如果需要在进程间传递数据,可以使用 ContentProvider 来实现。


二、 ContentProvider
Android 提供了一些主要数据类型的 ContentProvider,比如音频、视频、图片和私人通讯
录等。可在 android.provider 包下面找到一些 Android 提供的 ContentProvider。通过获得
这些 ContentProvider 可以查询它们包含的数据,当然前提是已获得适当的读取权限。
主要方法:
public boolean onCreate() 在创建 ContentProvider 时调用
public Cursor query(Uri, String[], String, String[], String) 用 于 查 询 指 定 Uri 的
ContentProvider,返回一个 Cursor
public Uri insert(Uri, ContentValues) 用于添加数据到指定 Uri 的 ContentProvider 中
public int update(Uri, ContentValues, String, String[]) 用于更新指定Uri的ContentProvider
中的数据
public int delete(Uri, String, String[]) 用于从指定 Uri 的 ContentProvider 中删除数据
public String getType(Uri) 用于返回指定的 Uri 中的数据的 MIME 类型
*如果操作的数据属于集合类型,那么 MIME 类型字符串应该以 vnd.android.cursor.dir/开头。
例如:要得到所有 person 记录的 Uri 为 content://contacts/person,那么返回的 MIME 类型
字符串为"vnd.android.cursor.dir/person"。
* 如 果 要 操 作 的 数 据 属 于 非 集 合 类 型 数 据 , 那 么 MIME 类 型 字 符 串 应 该 以
vnd.android.cursor.item/开头。
例如:要得到 id 为 10 的 person 记录的 Uri 为 content://contacts/person/10,那么返回的

MIME 类型字符串应为"vnd.android.cursor.item/person"。


三、 URI 的用法
每个 Content Provider 提供公共的 URI 来唯一标识其数据集,管理多个数据集(多个表格)
的 Content Provider 为每个都提供了单独的 URI.所提供的 URI 都以 content://作为前
缀”content://”模式表示数据由 Content Provider 来管理
如果自定义 Content Provider,则应该也是其 URI 定义一个常量,以简化客户端代码并让日
后更新更加简洁.Android为当前平台提供的 Content Provider 定义了 CONTENT_URI 常量.匹配
电话号码到联系人表格的 URI 和匹配保存联系人照片表格的 URI 分别如下.
android.provider.Contacts.Phones.CONTENT.URI;
android.provider.Contacts.Photos.CONTENT.URI;
URI 常量用于所有与 Content Provider 的交互中.每个 ContentResolver 方法使用 URI 作为其第
一个参数.它标识 ContentResolver 应该使用哪个 provider 以及其中的哪个表格.
下面是 Content URI 重要部分的总结
content://com.hua.employeeprovider/dba/001
上面的 URI 分四部分
第一部分:标准的前缀,用于标识该数据由 Content Provider 管理,它永远不用修改
第二部分:URI的authority部分,它标识该Content Provider.对于第三方应用,该部分应该是完整
的类名(小写)来保证唯一性,在<provider>元素的 authorities 属性中声明 authority.
第三部分: Content Provider 的路径部分,用于决定哪类数据被请求,如果 Content Provider 仅提
供一种数据类型,这部分可以没有.如果提供几种类型,包括子类型,这部分可以由几部分组成.
第四部分:被请求的特定的记录的ID值.这是被请求记录的_ID值.如果请求不仅限于单条记录
该部分及前面的斜线应该删除
经常需要解析 Uri,并从 Uri 中获取数据。Android 系统提供了两个用于操作 Uri 的工具类
UriMatcher
匹配 Uri。使用方法
UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sMatcher.addURI(“com.jiahui.provider.myprovider”, “person”, 1);
sMatcher.addURI(“com.jiahui.provider.myprovider”, “person/#”, 2);//#号为通配符
ContentUris
它用于在 Uri 后面追加一个 ID 或者解析出传入的 Uri 所带上的 ID 值
withAppendedId (Uri contentUri, long id)---用于为路径加上 ID 部分

parseId (Uri contentUri)----从路径中获取 ID 部分


四、 系统中义 预定义 Content Provider
Android 系统为常用数据类型提供了很多预定义的 Content Provider(声音,视频,图片,联系人),
它他大部分位于 android.provider 包中,开发人员可以查询这些 provider 经获得其中包含的信
息.android 系统提供的常见 Content Provider 说明如下
1,Browser:读取或修改书签,浏览历史或网络搜索.
2,CallLog: 查看或更新通话历史.
3,Contacts: 获取, 修改或保存联系人
4,LiveFolders:由 Content Provider 提供 内容的特定文件夹
5,MediaStrore:访问声音,视频和图片
6,Setting:查看和获取蓝牙设置,铃声和其它设备偏好.
7,SearchRecentSuggestions:该类能为应用程序创建简单的查询建议提供者,它基于近期
查询提供建议.
8,SyncStateContract:用于使用数据数组帐号关联数据的 Content Provider 约束,希望使用
标准方式保存数据的 provider 可以使用它.
9,UserDictionary:在可以预测文本输入时,提供用户定义的单词给输入法使用.应用程序

和输入法能增加到该字典,单词能关联频率信息和本地化信息.


五、 操作联系人
5.1 查询数据
在 Content Provider 中查询数据,开发人员需要知道以下信息:
标识该 Content Provider 的 URI
需要查询的数据字段名称
字段中数据的类型
如果需要查询特定记录,那么还需要知道该记录的 ID 值.
ContentResolver.query()或 Activity.managed-Query()方法都可以完成查询功能,这两个方
法使用的参数相同,都返回 Cursor 对象.其区别在于 managedQuery()方法记 Activity 来管理
Cursor 生命周期,而 query()方法则需要程序员自己管理.query()方法的声明如下
public final Cursor query(Uri uri,String[] projection,String selection,String[]
selectionArgs,String sortOrder)
Uri:用于查询的 Content Providerr URI 值
Projection:由需要查询 的列名组成的数组,如果为 NULL 则不胜枚举查询全部列
Selection:类似 SQL 中的 WHERE 子句,用于增加条件来完成数据过虑
SelectionArgs:用于替换 selection 中可以使用?表示的变量值
sortOrder:类似 SQL 中的 ORDER BY 子句,用于实现排序功能

返回值:Cursor 对象,它位于第一条记录之前,或者为 NULL


1,加入权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>

<uses-permission android:name="android.permission.WRITE_CONTACTS"/>


2,找出相前 URI
// raw_contacts表的uri
public static Uri uri_raw_contacts = Uri.parse("content://com.android.contacts/raw_contacts");
// data表的uri

public static Uri uri_data = Uri.parse("content://com.android.contacts/data");


3,查询代码
①查询出 raw_contact 表的内容,把_id 放到集合中
②根据查出的_id 到 data 里面查询相关的数据
③根据 data 表里的 mimetyp_id 去查询数据
④查询完成把数据添加到集合中

/***
* 查询所有的用户信息
* @param: @param resolver
* @return: List<Map<String,Object>>
*/
public static List<Map<String, Object>> queryAllContacts(ContentResolver resolver) {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Cursor c1 = resolver.query(uri_raw_contacts, null, null, null, null);
while (c1.moveToNext()) {
Map<String, Object> map = new HashMap<String, Object>();
int _id = c1.getInt(c1.getColumnIndex("_id"));// 从data表中取出记录的_id编号
map.put("_id", _id);// 存放到map里面
// 查找data表
Cursor c2 = resolver.query(uri_data, new String[] { "data1", "mimetype" },
raw_contact_id = ?",
new String[] { _id + "" }, // 通过指定的_id找该联系人的所有数据
null);
while (c2.moveToNext()) {
// 获取名字,电话号码,email
String data1 = c2.getString(c2.getColumnIndex("data1"));
String mimetype = c2.getString(c2.getColumnIndex("mimetype"));
if (mimetype.equals("vnd.android.cursor.item/name"))// 取出存放的电话号码的名字
{
map.put("name", data1);
} else if (mimetype.equals("vnd.android.cursor.item/phone_v2")) {
if (!map.containsKey("phone"))// 第一次放的时候
{
map.put("phone", data1);
} else// 第二次放的时候
{
String p = map.get("phone").toString();
map.put("phone", p + "&&" + data1);
}
} else if (mimetype.equals("vnd.android.cursor.item/email_v2"))// 取出邮件
{
if (!map.containsKey("email"))// 第一次放的时候
{
map.put("email", data1);
} else// 第二次放的时候
{
String p = map.get("email").toString();
map.put("email", p + "&&" + data1);
}
}
}
list.add(map);
}
return list;
}

注意: ContentResolver resolver 在是 Activity 或 Fragment 里面使用 getContentResolver()得到的


5.2 添加 数据
/***
* 添加
*/
public static void addContact(ContentResolver contentResolver, MyContact c) {
// 先向raw_contact里面插入数据
ContentValues values = new ContentValues();
Uri newUri = contentResolver.insert(uri_raw_contacts, values);
// 得到生成的ID
long _id = ContentUris.parseId(newUri);
// 然后用这个ID插入向data表里面插入为数据
values.clear();
values.put("raw_contact_id", _id);
values.put("data1", c.getName());
values.put("data2", c.getName());
// 定义类型
values.put("mimetype", "vnd.android.cursor.item/name");
contentResolver.insert(uri_data, values);
// 插入电话号码
values.clear();
values.put("raw_contact_id", _id);
values.put("data1", c.getPhone());
values.put("mimetype", "vnd.android.cursor.item/phone_v2");
contentResolver.insert(uri_data, values);
// 插入邮箱
values.clear();
values.put("raw_contact_id", _id);
values.put("data1", c.getEmail());
values.put("mimetype", "vnd.android.cursor.item/email_v2");
contentResolver.insert(uri_data, values);
System.out.println("------------插入成功");

}


5.3 修改 数据
/***
* 修改
*/
public static void updateContact(ContentResolver contentResolver, MyContact c) {
// 先向raw_contact里面插入数据
ContentValues values = new ContentValues();
// 是新录入的数据(只要和名字有关的都要进行修改)
values.put("display_name", c.getName());
values.put("display_name_alt", c.getName());
values.put("sort_key", c.getName());
values.put("sort_key_alt", c.getName());
contentResolver.update(uri_raw_contacts, values, "_id=?", new String[] { c.getId() +
"" });
// 修改data表
values.clear();
values.put("data1", c.getName());
values.put("data2", c.getName());
contentResolver.update(uri_data, values, "mimetype = ? and raw_contact_id = ?",// 确定
正确raw_contact_id,区分类型
new String[] { "vnd.android.cursor.item/name", c.getId() + "" });
// 修改电话号码
values.clear();
values.put("data1", c.getPhone());
//values.put("data2", Phone.TYPE_HOME);
contentResolver.update(uri_data, values, "mimetype = ? and raw_contact_id = ?",// 确定
正确raw_contact_id,区分类型
new String[] { "vnd.android.cursor.item/phone_v2", c.getId() + "" });
// 修改电话邮箱
values.clear();
values.put("data1", c.getEmail());
//values.put("data2", Email.TYPE_WORK);
contentResolver.update(uri_data, values, "mimetype = ? and raw_contact_id = ?",// 确定
正确raw_contact_id,区分类型
new String[] { "vnd.android.cursor.item/email_v2", c.getId() + "" });
System.out.println("------------修改成功");

}


5.4 删除数据
public static void deleteContact(ContentResolver contentResolver, String id) {
contentResolver.delete(uri_raw_contacts, "_id=?", new String[] { id });

}


六、 读取通话记录
/**
* 查询所有的通话记录
* @param resolver 访问共享数据的工具
*/
public static Cursor getAllCalls(ContentResolver resolver){
Uri uri = Uri.parse("content://call_log/calls");
System.out.println(CallLog.Calls.CONTENT_URI);
//第三个参数和第五个参数的关键字就不用写了
Cursor c = resolver.query(uri,
new String[]{
"_id","number","date","duration"
}, //返回指定的列,如果填写null返回该表中所有的列 ,列的信息填写到String[]
null, //where条件的参数"date=?,duration>?"
null, //where条件参数?对应的具体的集合new String[]{"2012-01-01","1*60*1000"}
"date desc" //排序"date desc"
);
return c;
}
/**
* 根据不同的类型获取电话记录
* type:通话类型 (1、来电记录;2、呼出记录;3、未接电话)
* @return
*/
public static Cursor getCallsType(ContentResolver resolver , int type){
Uri uri = Uri.parse("content://call_log/calls");
//第三个参数和第五个参数的关键字就不用写了
Cursor c = resolver.query(uri,
new String[]{
"_id","number","date","duration","type"
}, //返回指定的列,如果填写null返回该表中所有的列 ,列的信息填写到String[]
"type = ?", //where条件的参数"type =?"
new String[]{type +""}, //where条件参数?对应的具体的集合new String[]{"2"}
"date desc" //排序"date desc"
);
return c;

}


七、 读取短信
public class SMSHelper {
/**
* 查询所有短消息的信息
*
* @param resolver
* @return
*/
public static Cursor getAllMsgs(ContentResolver resolver) {
Uri uri = Uri.parse("content://sms/");
return resolver.query(uri, new String[] { "_id", "address", "body", "date" }, null, null,
"date desc");
}
/**
* 获取thread视图表的数据
*/
public static Cursor getThreadMsgs(ContentResolver resolver) {
// (* from threads --)
Uri uri = Uri.parse("content://sms/");
return resolver.query(uri, new String[] { "* from threads --" }, // 默认写// *就是所有

null, null, "date desc");
}
/**
* 通过thread_id获取电话号码
*/
public static String getAddressByThread_id(ContentResolver resolver, int thread_id) {
String address = null;
Uri uri = Uri.parse("content://sms/");
Cursor c = resolver.query(uri, new String[] { "address" }, "thread_id = ?", new String[]
{ thread_id + "" },
null);
if (c.moveToNext()) {
address = c.getString(c.getColumnIndex("address"));
}
return address;
}
/**
* 查询没有读取短消息的信息
* @param resolver
* @return
*/
public static Cursor getUnReadMsgs(ContentResolver resolver) {
Uri uri = Uri.parse("content://sms/");
return resolver.query(uri, new String[] { "_id", "address", "body", "date" }, "read = ?",
new String[] { "0" },
"date desc");
}

}


八、 自定义 ContentProvider
第一步:我们要继承 ContentProvider 类,实现自己的 ContentProvider。
第二步:ContentProvider 也是 Android 中的四大组件,因此也必须在 AndroidMainfest.xml 中
完成对 ContentProvider 的注册
<provider
android:authorities="com. example.provider.myprovider"
android:name=".MyProvider" >
</provider>
android:exported="true" (4.2 以后必须增加)
第三步:实现 ContentProvider 里面方法
public abstract boolean onCreate ()
在 ContentProvider 创建后被调用。
public abstract Uri insert (Uri uri, ContentValues values)
根据 Uri 插入 values 对就的数据
public abstract int delete (Uri uri, String selection, String[] selectionArgs)
根据 Uri 删除 selection 指定的条件所匹配的全部记录
public abstract int update (Uri uri, ContentValues values, String selection, String[] selectionArgs)
根据 Uri 修改 selection 指定的条件所匹配的全部记录
public abstract Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder)
根据 Uri 查询出 selection 指定的条件所匹配的全部记录,并且可以指定查询哪些列
(projection),以什么方式(sortOrder)排序
public abstract String getType (Uri uri)
返回当前 Uri 所数据的 MIME 类型,如果该 Uri 对应的数据可能包括多条记录,那么 MIME
类型字符串就是以 vnd.android.cursor.dir/开头,如果 Uri 对应的数据只包含一条记录,那么
MIME 类型字符串就是以 vnd.android.cursor.item/开头
第四步:使用 ContentResolver 操作 ContentProvider 中的数据
当外部应用需要对 ContentProvider 中的数据进行添加、删除、修改和查询操作时,需要使
用 ContentResolver 类来完成
获取 ContentResolver 对象
使用 Activity 提供的 getContentResolver()方法
public Uri insert(Uri uri, ContentValues values)
该方法用于往 ContentProvider 添加数据
public int delete(Uri uri, String selection, String[] selectionArgs)
该方法用于从 ContentProvider 删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
该方法用于更新 ContentProvider 中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String
sortOrder)
该方法用于从 ContentProvider 中获取数据
这些方法的第一个参数为 Uri,代表要操作的是哪个 ContentProvider 和对其中的什么数据
进行操作
假设给定的是: Uri.parse(“content://com. example.provider.personprovider/person/10”),
那么将会对主机名为 cn.example.provider.personprovider 的 ContentProvider 进行操作,操作
的数据为 person 表中 id 为 10 的记录

更多相关文章

  1. 【Android】ListView内数据的动态追加
  2. Android(安卓)Volley完全解析(三),定制自己的Request
  3. Android(安卓)Activity和Intent机制学习笔记
  4. Android音乐播放器-图片素材准备及布局
  5. delphi xe5 android 开发数据访问server端(一)
  6. Android-低功耗蓝牙(BLE)-客户端(主机/中心设备)和服务端(从机/
  7. Android学习之Intent实现页面跳转
  8. android 线程更新view及数据传送
  9. Android(安卓)setTag()/getTag()-

随机推荐

  1. Android输入分析
  2. Android学习路线权威指南
  3. Android开发之鬼迷心窍(二)
  4. Android的反编译和代码混淆
  5. 【Android 周末回眸】2010.11.13-11.20
  6. 在Android上实现HttpServer的示例代码
  7. 在Android中使用AspectJX框架遇到的配置
  8. android内所使用的资源类型
  9. [原]如何用Android NDK编译FFmpeg
  10. 传感器使用简介