联系人提供程序是一个强大而又灵活的 Android 组件,用于管理设备上联系人相关数据的中央存储区。 联系人提供程序是您在设备的联系人应用中看到的数据源,您也可以在自己的应用中访问其数据,并可在设备与在线服务之间传送数据。 提供程序储存有多种数据源,由于它会试图为每个联系人管理尽可能多的数据,因此造成其组织结构非常复杂。 为此,该提供程序的 API 包含丰富的协定类和接口,为数据检索和修改提供便利。
联系人提供程序是 Android 内容提供程序的一个组件。它保留了三种类型的联系人数据,每一种数据都对应提供程序提供的一个表,如图 1 所示:
这三个表通常以其协定类的名称命名。这些类定义表所使用的内容 URI、列名称及列值相应的常量:
ContactsContract.Contacts 表
表示不同联系人的行,基于聚合的原始联系人行。
ContactsContract.RawContacts 表
包含联系人数据摘要的行,针对特定用户帐户和类型。
ContactsContract.Data 表
包含原始联系人详细信息(例如电子邮件地址或电话号码)的行。
由 ContactsContract 中的协定类表示的其他表是辅助表,联系人提供程序利用它们来管理其操作,或为设备的联系人或电话应用中的特定功能提供支持。
注意:原始联系人的大部分数据并不存储在 ContactsContract.RawContacts 表内,而是存储在 ContactsContract.Data 表中的一行或多行内。每个数据行都有一个 Data.RAW_CONTACT_ID 列,其中包含其父级 ContactsContract.RawContacts 行的 RawContacts._ID 值。
所以你可以理解为每一个联系人在Contacts表中只记录了一次,即一条信息,记录了一些基本信息如:id,姓名等,它也记录了每一个联系人的RawContacts 表,你可以通过RawContacts 表查出联系人的CONTACT_ID,RawContacts 表中也不包括联系人的详细信息,你可以通过CONTACT_ID在Data 表中查询,注意,当你在Data 表中查询时,可能会查询到几条记录,例如一个联系人可能有几个多个号码,此时你在通过CONTACT_ID查询号码时,就会出现多条记录,也就说你可以通过Data表可以查到联系人的具体信息。你可能会问我要是同时查询电话,邮箱等多个信息怎么办,在Data表中有一个字段叫Data.MIMETYPE,该字段指定该条记录是什么类型(邮箱或电话),而邮箱和电话对应的字段都为Data.DATA1所以你的查询语句可以写为:
Cursor cursor=context.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
new String[]{Data.MIMETYPE,Data.DATA1},
Data.RAW_CONTACT_ID+" = ?",
new String[]{你要查询的联系人的id},
null);
if(cursor.moveToFirst()){
do{
if(Data.MIMETYPE=Email.CONTENT_ITEM_TYPE){
String email=cursor.getString(cursor.getColumnIndex(Data.DATA1));
}
if(Data.MIMETYPE=Phone.CONTENT_ITEM_TYPE){
String phone=cursor.getString(cursor.getColumnIndex(Data.DATA1));
}
}while (cursor.moveToNext());
cursor.close();
}
所以你可以看出每一条记录都代表一条信息,它不同时包括电话和邮箱,这也对应了图1所要表达的意思。一个联系的信息可能需要多个Data表来记录。
闲话少说如何对联系人进行增删改查,直接上代码。
增(insert):
ContentValues values = new ContentValues();
ContentResolver resolver = context.getContentResolver();
long RAW_CONTACT_ID = ContentUris.parseId(resolver.insert(RawContacts.CONTENT_URI, values));//先插入一条新的RawContacts表记录
//添加姓名
values.clear();
values.put(Data.RAW_CONTACT_ID, RAW_CONTACT_ID);
values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
values.put(StructuredName.DISPLAY_NAME, employee.getPerson_name());
resolver.insert(Data.CONTENT_URI, values);
//添加电话号码 tel_num是一个String数组
for (int i = 0; i <tel_num.length ; i++) {
values.clear();
values.put(Data.RAW_CONTACT_ID, RAW_CONTACT_ID);
values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
values.put(Phone.TYPE, Phone.TYPE_CUSTOM);
values.put(Phone.NUMBER, tel_num[i]);
resolver.insert(Data.CONTENT_URI, values);
}
//添加邮箱 email是一个String数组
for (int i = 0; i < email.length; i++) {
values.clear();
values.put(Data.RAW_CONTACT_ID, RAW_CONTACT_ID);
values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
values.put(Email.TYPE, Email.TYPE_CUSTOM);
values.put(Email.ADDRESS, email[i]);
resolver.insert(Data.CONTENT_URI, values);
}
删(Delete)
ArrayList<ContentProviderOperation> ops =
new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)
.withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
改(Update)
ArrayList<ContentProviderOperation> ops =
new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
.withValue(Email.DATA, "somebody@android.com")
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
查(Query):
Cursor c = getContentResolver().query(Data.CONTENT_URI,
new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},
Data.CONTACT_ID + "=?" + " AND "
+ Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",
new String[] {String.valueOf(contactId)}, null);
在上面的增删改查操作中都是在Data表中的操作,goole API是推荐这么做的,你可以参照如下的api介绍
Contacts 这个api中给我们提出了一些查询建议可以好好看看。
RawContacts
Data
其实gooleAPI为我们做了更细致的划分“类型专用列名称类”,如StructuredName(姓名),Photo(电话),Email(邮箱)等专用类。所以当我们查询电话时可以这么写:
Uri uri= Uri.withAppendedPath(Phone.CONTENT_FILTER_URI,tel_num);
Cursor cursor=context.getContentResolver().query(uri,new String[]{Phone.CONTACT_ID,Phone.DISPLAY_NAME},
null,null,null);
这里介绍一下Uri.withAppendedPath(Uri uri,String s)方法,它可以返回一个具体指向的uri,比如你传入了一个电话号码或contact_id。就可以直接查询到对应下的联系人信息。当我们在对联系人进行查询的时候这里要传入的uri要指向CONTENT_FILTER_URI而不是CONTENT_URI。
注意当我们插入相同的联系人时(这里指添加的信息完全相同)系统会自动识别是否已添加,而且只添加一条。
有错误欢迎指正,共同进步