Android-->获取所有联系人以及所有的字段(联系人头像,邮箱,地址,公司等)

本文测试平台: Android 6.0 , API 23

辅助阅读:
Android官网有关联系人的开发指南:
https://developer.android.com/guide/topics/providers/contacts-provider.html

相关API:
https://developer.android.com/reference/android/provider/ContactsContract.html

所有字段和MIMETYPE声明:
https://developer.android.com/reference/android/provider/ContactsContract.Data.html

准备好了吗?


1:获取所有联系人的id

final ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, new String[]{"_id"}, null, null, null);
//cursor.getCount() 就是联系人的总数

枚举所有联系人的id:

if (cursor != null && cursor.getCount() > 0) {
    if (cursor.moveToFirst()) {
        do {
            int contactIdIndex = cursor.getColumnIndex(ContactsContract.Contacts._ID);//获取 id 所在列的索引
            String contactId = cursor.getString(contactIdIndex);//联系人id
            //do something...
        } while (cursor.moveToNext());
        cursor.close();
    }
}

2:通过联系人的id,获取所有字段值
通过步骤1, 得到了联系人的id(contactId).

/**
* 根据MIMETYPE类型, 返回对应联系人的data1字段的数据
*/
private String getData1(final ContentResolver contentResolver, String contactId, final String mimeType) {
  StringBuilder stringBuilder = new StringBuilder();

  Cursor dataCursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
          new String[]{ContactsContract.Data.DATA1},
          ContactsContract.Data.CONTACT_ID + "=?" + " AND "
                  + ContactsContract.Data.MIMETYPE + "='" + mimeType + "'",
          new String[]{String.valueOf(contactId)}, null);
  if (dataCursor != null && dataCursor.getCount() > 0) {
      if (dataCursor.moveToFirst()) {
          do {
              stringBuilder.append(dataCursor.getString(dataCursor.getColumnIndex(ContactsContract.Data.DATA1)));
              stringBuilder.append("_");//多个值,之间的分隔符.可以自定义;
          } while (dataCursor.moveToNext());
      }
      dataCursor.close();
  }

  return stringBuilder.toString();
}

上面的方法,封装了取值的过程. 其实很容易看懂;

ContactsContract.Data.DATA1 -->就是包含值的字段名,也就是需要返回的字段;
contactId mimeType -->这2个查询的条件.
//其中contactId表示联系人的id,就是对应的那个联系人;
//mimeType, 这个表示,你需要获取联系人的什么字段.(比如,邮箱,公司,地址等)
//这个是常量值, 后面会介绍取值范围.

3:所有字段的MIMETYPE解释

String[] MIMETYPES = new String[]{
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE,//联系人名称
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,//联系人电话(可能包含多个)
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,//邮箱(多个)
ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE,//公司
ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE,//备注
ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE,//地址
ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE,//网站
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Relation.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
};

4:使用方法:
只需要把 联系人的id 和 MIMETYPE类型, 作为参数, 传递给步骤2的方法中.即可;


当然, 你也可以通过以下方法获取信息:

/*联系人电话信息*/
Cursor contactsCursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,//注意这个uri
        null,
        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId,//contactId 是上面提到过的联系人id
        null, null);
        //
    int phoneIndex = contactsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);//获取联系人 号码的索引
    int nameIndex = contactsCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);//获取 名字 所在列的索引
 //
 final String phoneNumber = contactsCursor.getString(phoneIndex);//联系人的号码
 final String name = contactsCursor.getString(nameIndex);//联系人名字
//
    contactsCursor.close();//记得close
}

/*联系人邮箱信息*/
Cursor emailCursor = contentResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,//注意URI
        null,
        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId,
        null, null);
//
int emailIndex = emailCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA);
//
 final String email = emailCursor.getString(emailIndex);//联系人邮箱
//
    emailCursor.close();
}

//这种方式, 我暂时还无法获取所有的字段...聪明的你,肯定比我厉害.

2017-01-08更新:
以上方法完全可行, 补充打印联系人的所有字段,及其值:

//此方法可以打印所有字段的详细信息
private static void logData(final ContentResolver contentResolver, String contactId) {
     Cursor dataCursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
             null,
             ContactsContract.Data.CONTACT_ID + "=?",
             new String[]{String.valueOf(contactId)}, null);
     if (dataCursor != null) {
         if (dataCursor.getCount() > 0) {
             L.e("----------------------start--------------------");
             L.i("数量:" + dataCursor.getCount() + " 列数:" + dataCursor.getColumnCount());
             if (dataCursor.moveToFirst()) {
                 do {
                     for (int i = 0; i < dataCursor.getColumnCount(); i++) {
                         final String columnName = dataCursor.getColumnName(i);
                         final int columnIndex = dataCursor.getColumnIndex(columnName);
                         final int type = dataCursor.getType(columnIndex);
                         String data = "", ty = "";
                         if (type == Cursor.FIELD_TYPE_NULL) {
                             ty = "NULL";
                             data = "空值";
                         } else if (type == Cursor.FIELD_TYPE_BLOB) {
                             ty = "BLOB";
                             data = String.valueOf(dataCursor.getBlob(columnIndex));
                         } else if (type == Cursor.FIELD_TYPE_FLOAT) {
                             ty = "FLOAT";
                             data = String.valueOf(dataCursor.getFloat(columnIndex));
                         } else if (type == Cursor.FIELD_TYPE_INTEGER) {
                             ty = "INTEGER";
                             data = String.valueOf(dataCursor.getInt(columnIndex));
                         } else if (type == Cursor.FIELD_TYPE_STRING) {
                             ty = "STRING";
                             data = dataCursor.getString(columnIndex);
                         }

                         L.i("第" + i + "列->名称:" + columnName + " 索引:" + columnIndex + " 类型:" + ty + " 值:" + data);
                     }
                 } while (dataCursor.moveToNext());
             }
             L.e("------------------------end---------------------");
         }
         dataCursor.close();
     }
 }
//输出结果大致如下:
第0列->名称:sort_key 索引:0 类型:STRING 值:熊志文
第1列->名称:photo_uri 索引:1 类型:STRING 值:content://com.android.contacts/display_photo/833
第2列->名称:status_label 索引:2 类型:NULL 值:空值
第3列->名称:status_ts 索引:3 类型:NULL 值:空值
第4列->名称:status_res_package 索引:4 类型:NULL 值:空值
第5列->名称:display_name 索引:5 类型:STRING 值:熊志文
第6列->名称:last_time_used 索引:6 类型:NULL 值:空值
第7列->名称:phone_number 索引:7 类型:NULL 值:空值
第8列->名称:mimetype 索引:8 类型:STRING 值:vnd.android.cursor.item/phone_v2
第9列->名称:phonebook_label_alt 索引:9 类型:STRING 值:X
第10列->名称:data6 索引:10 类型:NULL 值:空值
第11列->名称:version 索引:11 类型:INTEGER 值:5
第12列->名称:photo_id 索引:12 类型:INTEGER 值:2476
第13列->名称:data3 索引:13 类型:NULL 值:空值
第14列->名称:custom_ringtone 索引:14 类型:NULL 值:空值
第15列->名称:times_contacted 索引:15 类型:INTEGER 值:0
第16列->名称:account_type_and_data_set 索引:16 类型:STRING 值:com.meizu.account
第17列->名称:dirty 索引:17 类型:INTEGER 值:0
第18列->名称:data7 索引:18 类型:NULL 值:空值
第19列->名称:data15 索引:19 类型:NULL 值:空值
第20列->名称:address 索引:20 类型:INTEGER 值:-2
第21列->名称:raw_contact_is_user_profile 索引:21 类型:INTEGER 值:0
第22列->名称:data_set 索引:22 类型:NULL 值:空值
第23列->名称:phonebook_label 索引:23 类型:STRING 值:X
第24列->名称:data10 索引:24 类型:NULL 值:空值
第25列->名称:organization_note 索引:25 类型:NULL 值:空值
第26列->名称:contact_type 索引:26 类型:INTEGER 值:0
第27列->名称:res_package 索引:27 类型:NULL 值:空值
第28列->名称:account_type 索引:28 类型:STRING 值:com.meizu.account
第29列->名称:data11 索引:29 类型:NULL 值:空值
第30列->名称:display_name_alt 索引:30 类型:STRING 值:熊志文
第31列->名称:lookup 索引:31 类型:STRING 值:3303r692-984CA4C69394.3303r969-984CA4C69394
第32列->名称:phonetic_name 索引:32 类型:NULL 值:空值
第33列->名称:last_time_contacted 索引:33 类型:INTEGER 值:0
第34列->名称:contact_last_updated_timestamp 索引:34 类型:INTEGER 值:1331690502
第35列->名称:data13 索引:35 类型:NULL 值:空值
第36列->名称:in_visible_group 索引:36 类型:INTEGER 值:1
第37列->名称:chat_capability 索引:37 类型:NULL 值:空值
第38列->名称:data9 索引:38 类型:NULL 值:空值
第39列->名称:carrier_presence 索引:39 类型:INTEGER 值:0
第40列->名称:data_sync1 索引:40 类型:NULL 值:空值
第41列->名称:sort_key_alt 索引:41 类型:STRING 值:熊志文
第42列->名称:contact_presence 索引:42 类型:NULL 值:空值
第43列->名称:data_version 索引:43 类型:INTEGER 值:1
第44列->名称:phonetic_name_style 索引:44 类型:STRING 值:0
第45列->名称:name_raw_contact_id 索引:45 类型:INTEGER 值:692
第46列->名称:raw_contact_id 索引:46 类型:INTEGER 值:969
第47列->名称:send_to_voicemail 索引:47 类型:INTEGER 值:0
第48列->名称:data4 索引:48 类型:STRING 值:+8615070989512
第49列->名称:data12 索引:49 类型:NULL 值:空值
第50列->名称:contact_status 索引:50 类型:NULL 值:空值
第51列->名称:contact_status_label 索引:51 类型:NULL 值:空值
第52列->名称:pinned 索引:52 类型:INTEGER 值:0
第53列->名称:status_icon 索引:53 类型:NULL 值:空值
第54列->名称:status 索引:54 类型:NULL 值:空值
第55列->名称:data1 索引:55 类型:STRING 值:15070989512
第56列->名称:mz_last_op_package 索引:56 类型:NULL 值:空值
第57列->名称:phonebook_bucket 索引:57 类型:INTEGER 值:24
第58列->名称:data_sync2 索引:58 类型:NULL 值:空值
第59列->名称:contact_status_res_package 索引:59 类型:NULL 值:空值
第60列->名称:in_default_directory 索引:60 类型:INTEGER 值:1
第61列->名称:_id 索引:61 类型:INTEGER 值:3255
第62列->名称:hash_id 索引:62 类型:NULL 值:空值
第63列->名称:is_super_primary 索引:63 类型:INTEGER 值:0
第64列->名称:data5 索引:64 类型:NULL 值:空值
第65列->名称:contact_id 索引:65 类型:INTEGER 值:969
第66列->名称:data8 索引:66 类型:NULL 值:空值
第67列->名称:is_primary 索引:67 类型:INTEGER 值:1
第68列->名称:data_sync4 索引:68 类型:NULL 值:空值
第69列->名称:record_type 索引:69 类型:INTEGER 值:0
第70列->名称:has_phone_number 索引:70 类型:INTEGER 值:1
第71列->名称:sns_type 索引:71 类型:INTEGER 值:0
第72列->名称:display_name_source 索引:72 类型:INTEGER 值:40
第73列->名称:photo_file_id 索引:73 类型:INTEGER 值:833
第74列->名称:data_sync3 索引:74 类型:NULL 值:空值
第75列->名称:backup_id 索引:75 类型:NULL 值:空值
第76列->名称:data14 索引:76 类型:NULL 值:空值
第77列->名称:contact_status_ts 索引:77 类型:NULL 值:空值
第78列->名称:phonebook_bucket_alt 索引:78 类型:INTEGER 值:24
第79列->名称:mode 索引:79 类型:NULL 值:空值
第80列->名称:data2 索引:80 类型:STRING 值:7
第81列->名称:group_sourceid 索引:81 类型:NULL 值:空值
第82列->名称:starred 索引:82 类型:INTEGER 值:0
第83列->名称:photo_thumb_uri 索引:83 类型:STRING 值:content://com.android.contacts/contacts/969/photo
第84列->名称:times_used 索引:84 类型:NULL 值:空值
第85列->名称:contact_status_icon 索引:85 类型:NULL 值:空值
第86列->名称:distance 索引:86 类型:INTEGER 值:-1
第87列->名称:contact_chat_capability 索引:87 类型:NULL 值:空值
第88列->名称:account_name 索引:88 类型:STRING 值:8441299
第89列->名称:sourceid 索引:89 类型:NULL 值:空值

附加获取头像的方法:

/**
* 获取联系人的图片
*/
public static Bitmap getPhoto(final ContentResolver contentResolver, String contactId) {
   Bitmap photo = null;
   Cursor dataCursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
           new String[]{"data15"},
           ContactsContract.Data.CONTACT_ID + "=?" + " AND "
                   + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'",
           new String[]{String.valueOf(contactId)}, null);
   if (dataCursor != null) {
       if (dataCursor.getCount() > 0) {
           dataCursor.moveToFirst();
           byte[] bytes = dataCursor.getBlob(dataCursor.getColumnIndex("data15"));
           if (bytes != null) {
               photo = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
           }
       }
       dataCursor.close();
   }
   return photo;
}

开源地址:https://github.com/angcyo/ContactsPicker


至此: 文章就结束了,如有疑问: QQ群:274306954 欢迎您的加入.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容