本文仅作为自己的学习笔记,如需查看前辈的原文请[链接](https://blog.csdn.net/wssiqi/article/details/8132603)
1.获取联系人姓名
一个简单的例子,这个函数获取设备上所有的联系人ID和联系人NAME。
-
public void fetchAllContacts() {
-
ContentResolver contentResolver =
this.getContentResolver();
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
null,
null,
null,
null);
-
cursor.getCount();
-
while(cursor.moveToNext()) {
-
System.out.println(cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts._ID)));
-
System.out.println(cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts.DISPLAY_NAME)));
-
}
-
cursor.close();
-
}
执行结果:
-
11-
05
14:
13:
09.987: I/System.out(
4692):
13
-
11-
05
14:
13:
09.987: I/System.out(
4692): 张三
-
11-
05
14:
13:
09.987: I/System.out(
4692):
31
-
11-
05
14:
13:
09.987: I/System.out(
4692): 李四
解释:
ContentResolver contentResolver = this.getContentResolver();
this在这里指的是MainActivity,ContentResolver直译为内容解析器,什么东东?Android中程序间数据的共享是通过Provider/Resolver进行的。提供数据(内容)的就叫Provider,Resovler提供接口对这个内容进行解读。
在这里,系统提供了联系人的Provider,那么我们就需要构建一个Resolver来读取联系人的内容。
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
null,
null,
null,
null);
根据Android文档,
public final Cursor query (Uri uri, String[] projection,String selection,String[] selectionArgs, String sortOrder)
第一个参数,uri,rui是什么呢?好吧,上面我们提到了Android提供内容的叫Provider,那么在Android中怎么区分各个Provider?有提供联系人的,有提供图片的等等。所以就需要有一个唯一的标识来标识这个Provider,Uri就是这个标识,android.provider.ContactsContract.Contacts.CONTENT_URI就是提供联系人的内容提供者,可惜这个内容提供者提供的数据很少。第二个参数,projection,真不知道为什么要用这个单词,这个参数告诉Provider要返回的内容(列Column),比如Contacts Provider提供了联系人的ID和联系人的NAME等内容,如果我们只需要NAME,那么我们就应该使用:
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
new String[]{android.provider.ContactsContract.Contacts.DISPLAY_NAME},
null,
null,
null);
当然,下面打印的你就只能显示NAME了,因为你返回的结果不包含ID。用null表示返回Provider的所有内容(列Column)。
第三个参数,selection,设置条件,相当于SQL语句中的where。null表示不进行筛选。如果我们只想返回名称为张三的数据,第三个参数应该设置为:
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
new String[]{android.provider.ContactsContract.Contacts.DISPLAY_NAME},
-
android.provider.ContactsContract.Contacts.DISPLAY_NAME +
"='张三'",
null,
null);
结果:
11-05 15:30:32.188: I/System.out(10271): 张三
第四个参数,selectionArgs,这个参数是要配合第三个参数使用的,如果你在第三个参数里面有?,那么你在selectionArgs写的数据就会替换掉?,
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
new String[]{android.provider.ContactsContract.Contacts.DISPLAY_NAME},
-
android.provider.ContactsContract.Contacts.DISPLAY_NAME +
"=?",
-
new String[]{
"张三"},
null);
效果和上面一句的效果一样。
第五个参数,sortOrder,按照什么进行排序,相当于SQL语句中的Order by。如果想要结果按照ID的降序排列:
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
null,
null,
null, android.provider.ContactsContract.Contacts._ID +
" DESC");
结果:
-
11-
05
16:
00:
32.808: I/System.out(
12523):
31
-
11-
05
16:
00:
32.808: I/System.out(
12523): 李四
-
11-
05
16:
00:
32.817: I/System.out(
12523):
13
-
11-
05
16:
00:
32.817: I/System.out(
12523): 张三
升序,其实默认排序是升序,+" ASC"写不写效果都一样:
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
null,
null,
null, android.provider.ContactsContract.Contacts._ID +
" ASC");
结果:
-
11-
05
15:
59:
10.327: I/System.out(
12406):
13
-
11-
05
15:
59:
10.327: I/System.out(
12406): 张三
-
11-
05
15:
59:
10.327: I/System.out(
12406):
31
-
11-
05
15:
59:
10.327: I/System.out(
12406): 李四
原文链接链接
1.获取联系人详细信息
在(一)中我们只是获取了联系人的ID和NAME,但是这是远远不够的,怎么样获取其他的值呢?
-
public void fetchContactInformation() {
-
String id,name,phoneNumber,email;
-
ContentResolver contentResolver =
this.getContentResolver();
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
null,
null,
null,
null);
-
while(cursor.moveToNext()) {
-
id=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts._ID));
-
name=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts.DISPLAY_NAME));
-
-
//Fetch Phone Number
-
Cursor phoneCursor = contentResolver.query(
-
android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
-
null, android.provider.ContactsContract.CommonDataKinds.Phone.CONTACT_ID+
"="+id,
null,
null);
-
while(phoneCursor.moveToNext()) {
-
phoneNumber = phoneCursor.getString(
-
phoneCursor.getColumnIndex(android.provider.ContactsContract.CommonDataKinds.Phone.NUMBER));
-
System.out.println(
"id="+id+
" name="+name+
" phoneNumber="+phoneNumber);
-
}
-
phoneCursor.close();
-
-
//Fetch email
-
Cursor emailCursor = contentResolver.query(
-
android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI,
-
null, android.provider.ContactsContract.CommonDataKinds.Email.CONTACT_ID+
"="+id,
null,
null);
-
while(emailCursor.moveToNext()) {
-
email = emailCursor.getString(
-
emailCursor.getColumnIndex(android.provider.ContactsContract.CommonDataKinds.Email.DATA));
-
System.out.println(
"id="+id+
" name="+name+
" email="+email);
-
}
-
emailCursor.close();
-
}
-
cursor.close();
-
}
结果:
-
11-
06
14:
38:
32.049: I/System.out(
26534): id=
4 name=张三 phoneNumber=
1-
234-
56
-
11-
06
14:
38:
32.138: I/System.out(
26534): id=
5 name=李四 phoneNumber=
654-
321
-
11-
06
14:
38:
32.138: I/System.out(
26534): id=
5 name=李四 phoneNumber=
987-
654-
321
-
11-
06
14:
38:
32.188: I/System.out(
26534): id=
5 name=李四 email=wssiqi@
126.com
在这里,我们通过
android.provider.ContactsContract.Contacts.CONTENT_URI 来获取联系人的ID和NAME
android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI 获取联系人的电话号码
android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI 获取联系人的邮箱地址
关键是ContactsContract下面有很多类,很不容易找到到底哪个类包含我们需要的内容。怎样通过比较简单的方法获取所有信息呢?
为了更好的解决这个问题,我们需要先分析联系人的信息是怎样存储在Android上的。
2.Android 联系人存储方式
Android是将联系人信息存储在Sqlite数据库中的,如果想知道Sqlite的详细信息,请百度或者Google。
如何查看Sqlite中Contacts数据库,请参考http://www.cnblogs.com/luxiaofeng54/archive/2011/03/15/1985183.html,我也是从这里了解的。
2.1 联系人 表Contacts
上面这张图就是表contacts的内容,可以从中看出这张表的信息,常用的有_id,display_name
-
contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
null,
null,
null,
null);
编译后的内容是这样的:
SELECT times_contacted, contacts_status_updates.status AS contact_status, custom_ringtone, has_phone_number, contacts_status_updates.status_label AS contact_status_label, lookup, contacts_status_updates.status_icon AS contact_status_icon, last_time_contacted, display_name, in_visible_group, _id, starred, agg_presence.mode AS contact_presence, contacts_status_updates.status_res_package AS contact_status_res_package, contacts_status_updates.status_ts AS contact_status_ts, photo_id, send_to_voicemail FROM view_contacts_restricted LEFT OUTER JOIN agg_presence ON (_id = presence_contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id)
省略掉我们不关心的内容,就成了这个:
SELECT * FROM view_contacts_restricted
view_contacts_restricted是一个视图,你可以把它当作一个表,view_contacts_restricted的主要内容来自于表contacts,所以我们只能从android.provider.ContactsContract.Contacts.CONTENT_URI获取到ID和DisplayName,要获取到其他信息,就需要从data表获取。
2.2 联系人 表data
这个表就是存储联系人相关信息的表。mimetype表如下:
获取Phone Number的URI:
-
contentResolver.query(android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
-
null,
null,
null,
null);
编译后的内容:
SELECT data_version, contact_id, lookup, data12, data11, data10, mimetype, data15, data14, data13, data_sync1, data_sync3, data_sync2, data_sync4, account_type, custom_ringtone, status_updates.status AS status, data1, data4, data5, data2, data3, data8, data9, group_sourceid, data6, account_name, data7, display_name, in_visible_group, contacts_status_updates.status_res_package AS contact_status_res_package, is_primary, contacts_status_updates.status_ts AS contact_status_ts, raw_contact_id, times_contacted, contacts_status_updates.status AS contact_status, status_updates.status_res_package AS status_res_package, status_updates.status_icon AS status_icon, contacts_status_updates.status_icon AS contact_status_icon, presence.mode AS mode, version, last_time_contacted, res_package, _id, status_updates.status_ts AS status_ts, dirty, is_super_primary, photo_id, send_to_voicemail, contacts_status_updates.status_label AS contact_status_label, status_updates.status_label AS status_label, starred, agg_presence.mode AS contact_presence, sourceid FROM view_data_restricted data LEFT OUTER JOIN agg_presence ON (agg_presence.presence_contact_id=contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id) LEFT OUTER JOIN presence ON (presence_data_id=data._id) LEFT OUTER JOIN status_updates ON (status_updates.status_update_data_id=data._id) WHERE (1 AND mimetype = 'vnd.android.cursor.item/phone_v2')
主要的信息为:
SELECT * FROM view_data_restricted where mimetype = 'vnd.android.cursor.item/phone_v2'
获取Email的URI:
-
contentResolver.query(android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI,
-
null,
null,
null,
null);
编译后的内容:
SELECT data_version, contact_id, lookup, data12, data11, data10, mimetype, data15, data14, data13, data_sync1, data_sync3, data_sync2, data_sync4, account_type, custom_ringtone, status_updates.status AS status, data1, data4, data5, data2, data3, data8, data9, group_sourceid, data6, account_name, data7, display_name, in_visible_group, contacts_status_updates.status_res_package AS contact_status_res_package, is_primary, contacts_status_updates.status_ts AS contact_status_ts, raw_contact_id, times_contacted, contacts_status_updates.status AS contact_status, status_updates.status_res_package AS status_res_package, status_updates.status_icon AS status_icon, contacts_status_updates.status_icon AS contact_status_icon, presence.mode AS mode, version, last_time_contacted, res_package, _id, status_updates.status_ts AS status_ts, dirty, is_super_primary, photo_id, send_to_voicemail, contacts_status_updates.status_label AS contact_status_label, status_updates.status_label AS status_label, starred, agg_presence.mode AS contact_presence, sourceid FROM view_data_restricted data LEFT OUTER JOIN agg_presence ON (agg_presence.presence_contact_id=contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id) LEFT OUTER JOIN presence ON (presence_data_id=data._id) LEFT OUTER JOIN status_updates ON (status_updates.status_update_data_id=data._id) WHERE (1 AND mimetype = 'vnd.android.cursor.item/email_v2')
主要的信息为:
SELECT * FROM view_data_restricted where mimetype = 'vnd.android.cursor.item/email_v2'
可以看出,Phone number和Email的获取都是从同一张表获取的。 唯一的区别是 mimetype的类型不同。
view_data_restricted的主要内容来自于表data。
从表data可以看出,name,phone number,email存储的方式是一样的,都是data1,后面的data是更详细的信息,区分name,phone number,email 的唯一方式是mimetype_id,区分联系人的唯一标识是raw_contact_id,这个值是从上面的表contacts的_id获取的。
经过以上分析,我们可以知道,要想获取联系人的所有信息,需要先通过contacts表获取联系人ID,然后根据联系人的ID在表data获取想要的内容。
下面我们通过一个URI获取联系人的所有信息:
-
public void fetchContactInformationV2() {
-
String id;
-
String mimetype;
-
ContentResolver contentResolver =
this.getContentResolver();
-
//只需要从Contacts中获取ID,其他的都可以不要,通过查看上面编译后的SQL语句,可以看出将第二个参数
-
//设置成null,默认返回的列非常多,是一种资源浪费。
-
Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
-
new String[]{android.provider.ContactsContract.Contacts._ID},
null,
null,
null);
-
while(cursor.moveToNext()) {
-
id=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts._ID));
-
-
//从一个Cursor获取所有的信息
-
Cursor contactInfoCursor = contentResolver.query(
-
android.provider.ContactsContract.Data.CONTENT_URI,
-
new String[]{android.provider.ContactsContract.Data.CONTACT_ID,
-
android.provider.ContactsContract.Data.MIMETYPE,
-
android.provider.ContactsContract.Data.DATA1
-
},
-
android.provider.ContactsContract.Data.CONTACT_ID+
"="+id,
null,
null);
-
while(contactInfoCursor.moveToNext()) {
-
mimetype = contactInfoCursor.getString(
-
contactInfoCursor.getColumnIndex(android.provider.ContactsContract.Data.MIMETYPE));
-
String value = contactInfoCursor.getString(
-
contactInfoCursor.getColumnIndex(android.provider.ContactsContract.Data.DATA1));
-
if(mimetype.contains(
"/name")){
-
System.out.println(
"姓名="+value);
-
}
else
if(mimetype.contains(
"/im")){
-
System.out.println(
"聊天(QQ)账号="+value);
-
}
else
if(mimetype.contains(
"/email")) {
-
System.out.println(
"邮箱="+value);
-
}
else
if(mimetype.contains(
"/phone")) {
-
System.out.println(
"电话="+value);
-
}
else
if(mimetype.contains(
"/postal")) {
-
System.out.println(
"邮编="+value);
-
}
else
if(mimetype.contains(
"/photo")) {
-
System.out.println(
"照片="+value);
-
}
else
if(mimetype.contains(
"/group")) {
-
System.out.println(
"组="+value);
-
}
-
}
-
System.out.println(
"*********");
-
contactInfoCursor.close();
-
}
-
cursor.close();
-
}
结果:
-
11-
06
17:
16:
59.068: I/System.out(
3737): 电话=
1-
234-
56
-
11-
06
17:
16:
59.068: I/System.out(
3737): 姓名=张三
-
11-
06
17:
16:
59.068: I/System.out(
3737): *********
-
11-
06
17:
16:
59.108: I/System.out(
3737): 电话=
654-
321
-
11-
06
17:
16:
59.108: I/System.out(
3737): 姓名=李四
-
11-
06
17:
16:
59.108: I/System.out(
3737): 电话=
987-
654-
321
-
11-
06
17:
16:
59.108: I/System.out(
3737): 聊天(QQ)账号=
123456
-
11-
06
17:
16:
59.108: I/System.out(
3737): 邮箱=wssiqi@
126.com
-
11-
06
17:
16:
59.108: I/System.out(
3737): *********