Android读取、增删联系人(一)

本文仅作为自己的学习笔记,如需查看前辈的原文请[链接](https://blog.csdn.net/wssiqi/article/details/8132603)

1.获取联系人姓名

一个简单的例子,这个函数获取设备上所有的联系人ID和联系人NAME。


 
 
  1. public void fetchAllContacts() {
  2. ContentResolver contentResolver = this.getContentResolver();
  3. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  4. null, null, null, null);
  5. cursor.getCount();
  6. while(cursor.moveToNext()) {
  7. System.out.println(cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts._ID)));
  8. System.out.println(cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts.DISPLAY_NAME)));
  9. }
  10. cursor.close();
  11. }

执行结果:


 
 
  1. 11- 05 14: 13: 09.987: I/System.out( 4692): 13
  2. 11- 05 14: 13: 09.987: I/System.out( 4692): 张三
  3. 11- 05 14: 13: 09.987: I/System.out( 4692): 31
  4. 11- 05 14: 13: 09.987: I/System.out( 4692): 李四

解释:

ContentResolver contentResolver = this.getContentResolver();
 
 

this在这里指的是MainActivity,ContentResolver直译为内容解析器,什么东东?Android中程序间数据的共享是通过Provider/Resolver进行的。提供数据(内容)的就叫Provider,Resovler提供接口对这个内容进行解读。

在这里,系统提供了联系人的Provider,那么我们就需要构建一个Resolver来读取联系人的内容。


 
 
  1. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  2. 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,那么我们就应该使用:


 
 
  1. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  2. new String[]{android.provider.ContactsContract.Contacts.DISPLAY_NAME}, null, null, null);
当然,下面打印的你就只能显示NAME了,因为你返回的结果不包含ID。用null表示返回Provider的所有内容(列Column)。

第三个参数,selection,设置条件,相当于SQL语句中的where。null表示不进行筛选。如果我们只想返回名称为张三的数据,第三个参数应该设置为:


 
 
  1. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  2. new String[]{android.provider.ContactsContract.Contacts.DISPLAY_NAME},
  3. android.provider.ContactsContract.Contacts.DISPLAY_NAME + "='张三'", null, null);
结果:

11-05 15:30:32.188: I/System.out(10271): 张三

 
 
第四个参数,selectionArgs,这个参数是要配合第三个参数使用的,如果你在第三个参数里面有?,那么你在selectionArgs写的数据就会替换掉?,


 
 
  1. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  2. new String[]{android.provider.ContactsContract.Contacts.DISPLAY_NAME},
  3. android.provider.ContactsContract.Contacts.DISPLAY_NAME + "=?",
  4. new String[]{ "张三"}, null);

效果和上面一句的效果一样。

第五个参数,sortOrder,按照什么进行排序,相当于SQL语句中的Order by。如果想要结果按照ID的降序排列:


 
 
  1. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  2. null, null, null, android.provider.ContactsContract.Contacts._ID + " DESC");
结果:


 
 
  1. 11- 05 16: 00: 32.808: I/System.out( 12523): 31
  2. 11- 05 16: 00: 32.808: I/System.out( 12523): 李四
  3. 11- 05 16: 00: 32.817: I/System.out( 12523): 13
  4. 11- 05 16: 00: 32.817: I/System.out( 12523): 张三
升序,其实默认排序是升序,+" ASC"写不写效果都一样:


 
 
  1. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  2. null, null, null, android.provider.ContactsContract.Contacts._ID + " ASC");
结果:


 
 
  1. 11- 05 15: 59: 10.327: I/System.out( 12406): 13
  2. 11- 05 15: 59: 10.327: I/System.out( 12406): 张三
  3. 11- 05 15: 59: 10.327: I/System.out( 12406): 31
  4. 11- 05 15: 59: 10.327: I/System.out( 12406): 李四


原文链接链接

1.获取联系人详细信息

在(一)中我们只是获取了联系人的ID和NAME,但是这是远远不够的,怎么样获取其他的值呢?


 
 
  1. public void fetchContactInformation() {
  2. String id,name,phoneNumber,email;
  3. ContentResolver contentResolver = this.getContentResolver();
  4. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  5. null, null, null, null);
  6. while(cursor.moveToNext()) {
  7. id=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts._ID));
  8. name=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts.DISPLAY_NAME));
  9. //Fetch Phone Number
  10. Cursor phoneCursor = contentResolver.query(
  11. android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
  12. null, android.provider.ContactsContract.CommonDataKinds.Phone.CONTACT_ID+ "="+id, null, null);
  13. while(phoneCursor.moveToNext()) {
  14. phoneNumber = phoneCursor.getString(
  15. phoneCursor.getColumnIndex(android.provider.ContactsContract.CommonDataKinds.Phone.NUMBER));
  16. System.out.println( "id="+id+ " name="+name+ " phoneNumber="+phoneNumber);
  17. }
  18. phoneCursor.close();
  19. //Fetch email
  20. Cursor emailCursor = contentResolver.query(
  21. android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI,
  22. null, android.provider.ContactsContract.CommonDataKinds.Email.CONTACT_ID+ "="+id, null, null);
  23. while(emailCursor.moveToNext()) {
  24. email = emailCursor.getString(
  25. emailCursor.getColumnIndex(android.provider.ContactsContract.CommonDataKinds.Email.DATA));
  26. System.out.println( "id="+id+ " name="+name+ " email="+email);
  27. }
  28. emailCursor.close();
  29. }
  30. cursor.close();
  31. }


结果:


 
 
  1. 11- 06 14: 38: 32.049: I/System.out( 26534): id= 4 name=张三 phoneNumber= 1- 234- 56
  2. 11- 06 14: 38: 32.138: I/System.out( 26534): id= 5 name=李四 phoneNumber= 654- 321
  3. 11- 06 14: 38: 32.138: I/System.out( 26534): id= 5 name=李四 phoneNumber= 987- 654- 321
  4. 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


 
 
  1. contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  2. 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:


 
 
  1. contentResolver.query(android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
  2. 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:


 
 
  1. contentResolver.query(android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI,
  2. 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获取联系人的所有信息:


 
 
  1. public void fetchContactInformationV2() {
  2. String id;
  3. String mimetype;
  4. ContentResolver contentResolver = this.getContentResolver();
  5. //只需要从Contacts中获取ID,其他的都可以不要,通过查看上面编译后的SQL语句,可以看出将第二个参数
  6. //设置成null,默认返回的列非常多,是一种资源浪费。
  7. Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,
  8. new String[]{android.provider.ContactsContract.Contacts._ID}, null, null, null);
  9. while(cursor.moveToNext()) {
  10. id=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts._ID));
  11. //从一个Cursor获取所有的信息
  12. Cursor contactInfoCursor = contentResolver.query(
  13. android.provider.ContactsContract.Data.CONTENT_URI,
  14. new String[]{android.provider.ContactsContract.Data.CONTACT_ID,
  15. android.provider.ContactsContract.Data.MIMETYPE,
  16. android.provider.ContactsContract.Data.DATA1
  17. },
  18. android.provider.ContactsContract.Data.CONTACT_ID+ "="+id, null, null);
  19. while(contactInfoCursor.moveToNext()) {
  20. mimetype = contactInfoCursor.getString(
  21. contactInfoCursor.getColumnIndex(android.provider.ContactsContract.Data.MIMETYPE));
  22. String value = contactInfoCursor.getString(
  23. contactInfoCursor.getColumnIndex(android.provider.ContactsContract.Data.DATA1));
  24. if(mimetype.contains( "/name")){
  25. System.out.println( "姓名="+value);
  26. } else if(mimetype.contains( "/im")){
  27. System.out.println( "聊天(QQ)账号="+value);
  28. } else if(mimetype.contains( "/email")) {
  29. System.out.println( "邮箱="+value);
  30. } else if(mimetype.contains( "/phone")) {
  31. System.out.println( "电话="+value);
  32. } else if(mimetype.contains( "/postal")) {
  33. System.out.println( "邮编="+value);
  34. } else if(mimetype.contains( "/photo")) {
  35. System.out.println( "照片="+value);
  36. } else if(mimetype.contains( "/group")) {
  37. System.out.println( "组="+value);
  38. }
  39. }
  40. System.out.println( "*********");
  41. contactInfoCursor.close();
  42. }
  43. cursor.close();
  44. }
结果:


 
 
  1. 11- 06 17: 16: 59.068: I/System.out( 3737): 电话= 1- 234- 56
  2. 11- 06 17: 16: 59.068: I/System.out( 3737): 姓名=张三
  3. 11- 06 17: 16: 59.068: I/System.out( 3737): *********
  4. 11- 06 17: 16: 59.108: I/System.out( 3737): 电话= 654- 321
  5. 11- 06 17: 16: 59.108: I/System.out( 3737): 姓名=李四
  6. 11- 06 17: 16: 59.108: I/System.out( 3737): 电话= 987- 654- 321
  7. 11- 06 17: 16: 59.108: I/System.out( 3737): 聊天(QQ)账号= 123456
  8. 11- 06 17: 16: 59.108: I/System.out( 3737): 邮箱=wssiqi@ 126.com
  9. 11- 06 17: 16: 59.108: I/System.out( 3737): *********



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值