通讯录查询和添加

本文概要:
在获取通讯录的时候会遇到各种坑。虽然网上也有不少关于该部分的内容,但大多数不能满足我的需求。所以按照一贯的风格,自己动手丰衣足食。

通讯录中遇到的坑

通讯录是我们每天都会用到的应用,算是我们再也熟悉不过的。最近一段时间一直在做关于电话的应用,或多或少的会获取通讯录信息。这部分代码的分析网上有一大堆。感兴趣的同学可以自己搜索学习。但在我看来这部分的内容,其实还是有点复杂的。获取通讯录的时候会牵扯到很多张表,刚开始的时候确实会让人摸不着脉。特别是网上的资料,因为作者出发的角度不同,所以使用的API也会不一样。这样会给初学者带来很多烦恼,从而使他们无法清楚的知道该如何正确的定制属于他们的需要。

填坑

通讯录的使用无非就是查询、添加和删除。是的,你没有听错就是万能的增删改查。在这里我对查询和添加做了一个封装,在大多数情况下基本能够满足我们的需要了。

1、查询

查询的核心代码如下。

// 本地通讯录数据
 public List<Contacts> contacts; //这里的Contacts是我们自定义的类
 
//加载本地通讯录
 public void loadContacts() {
  contacts = new ArrayList<Contacts>();
  new AsyncTask<Object, Object, String>(){
   protected String doInBackground(Object... arg0) {
    String id;
    String mimetype;
    ContentResolver contentResolver = BaseApplication.getContextObject().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);
    Contacts contactitem;
    while(cursor.moveToNext()) {
     contactitem = new Contacts();//查询的要创建新的contacts对象
     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.CommonDataKinds.StructuredName.GIVEN_NAME, //用户名
         android.provider.ContactsContract.CommonDataKinds.Organization.COMPANY,//公司
         android.provider.ContactsContract.CommonDataKinds.Organization.TITLE,//职称
         android.provider.ContactsContract.CommonDataKinds.Phone.TYPE,//电话属性
         android.provider.ContactsContract.CommonDataKinds.Phone.NUMBER,// 电话号码
         android.provider.ContactsContract.CommonDataKinds.Email.TYPE,//邮件属性
         android.provider.ContactsContract.CommonDataKinds.Email.DATA,//邮件信息
         android.provider.ContactsContract.CommonDataKinds.Note.NOTE,//备注
         android.provider.ContactsContract.Data.DATA1,//查询的细节
         android.provider.ContactsContract.Data.DATA5
       }, 
       android.provider.ContactsContract.Data.CONTACT_ID+"="+id, null, null);
     while(contactInfoCursor.moveToNext()) {
      mimetype = contactInfoCursor.getString(
        contactInfoCursor.getColumnIndex(android.provider.ContactsContract.Data.MIMETYPE));

      if (mimetype.equals(StructuredName.CONTENT_ITEM_TYPE)) {
       String name = contactInfoCursor.getString(contactInfoCursor  
         .getColumnIndexOrThrow(android.provider.ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
       //LogUtils.E("====name==="+name);
       contactitem.setName(name);
      } else if (mimetype.equals(Organization.CONTENT_ITEM_TYPE)) {
       String org = contactInfoCursor.getString(contactInfoCursor  
         .getColumnIndexOrThrow(android.provider.ContactsContract.CommonDataKinds.Organization.COMPANY));
       String title = contactInfoCursor.getString(contactInfoCursor  
         .getColumnIndexOrThrow(android.provider.ContactsContract.CommonDataKinds.Organization.TITLE));
       String department = contactInfoCursor.getString(contactInfoCursor  
         .getColumnIndexOrThrow(android.provider.ContactsContract.CommonDataKinds.Organization.DEPARTMENT));
       //LogUtils.E("====org==="+org+","+title);
       contactitem.setOrganization(org);
       contactitem.setJobtitle(title);
       contactitem.setDepartment(department);
      } else if (mimetype.equals(Phone.CONTENT_ITEM_TYPE)) {
       String type = contactInfoCursor.getString(contactInfoCursor  
         .getColumnIndexOrThrow(android.provider.ContactsContract.CommonDataKinds.Phone.TYPE));
       String number;
       String phonename = null;
       int a = Integer.parseInt(type);
       switch (a){
       case Phone.TYPE_MOBILE:
        phonename = "mobile";
        break;
       case Phone.TYPE_MAIN:
        phonename = "main";
        break;
       case Phone.TYPE_HOME:
        phonename = "home";
        break;
       case Phone.TYPE_WORK:
        phonename = "work";
        break;
       case Phone.TYPE_FAX_WORK:
        phonename = "fax_work";
        break;
       case Phone.TYPE_FAX_HOME:
        phonename = "fax_home";
        break;
       case Phone.TYPE_OTHER:
        phonename = "other";
        break;
       case Phone.TYPE_CUSTOM:
        phonename = "custom";
        break;
       }
       number = contactInfoCursor.getString(contactInfoCursor  
         .getColumnIndexOrThrow(android.provider.ContactsContract.CommonDataKinds.Phone.NUMBER));
       //LogUtils.E("====phone==="+phonename+","+number);
       ContactFields cf = new ContactFields("Contact::Phone", phonename, number);
       contactitem.contact_fields.add(cf);

      } else if (mimetype.equals(Email.CONTENT_ITEM_TYPE)) {
       String type = contactInfoCursor.getString(contactInfoCursor  
         .getColumnIndexOrThrow(android.provider.ContactsContract.CommonDataKinds.Email.TYPE));
       String emailname = null;
       switch (Integer.parseInt(type)) {
       case Email.TYPE_WORK:
        emailname = "work";
        break;
       case Email.TYPE_CUSTOM:
        emailname = "custom";
        break;
       case Email.TYPE_MOBILE:
        emailname = "mobile";
        break;
       case Email.TYPE_HOME:
        emailname = "home";
        break;
       case Email.TYPE_OTHER:
        emailname = "other";
        break;
       }
       String date = contactInfoCursor.getString(contactInfoCursor  
         .getColumnIndexOrThrow(android.provider.ContactsContract.CommonDataKinds.Email.DATA));
       //LogUtils.E("====email==="+emailname+","+date);
       ContactFields cf = new ContactFields("Contact::Email", emailname, date);//ContactFields也是我自定义的一个对象,你可以根据需要定义自己的bean类
       contactitem.contact_fields.add(cf);

      } else if (mimetype.equals(Note.CONTENT_ITEM_TYPE)) {
       String note = contactInfoCursor.getString(
         contactInfoCursor.getColumnIndex(android.provider.ContactsContract.CommonDataKinds.Note.NOTE));
//       LogUtils.E("====note==="+note);
       contactitem.setNote(note);
      }
     }
     contacts.add(contactitem);
//     System.out.println("*********");
     contactInfoCursor.close();
    }
    cursor.close();
   
    return null;
   }
   
  }.execute();
 }

在上面的代码中mimetype属性是十分重要的。它是android.provider.ContactsContract.Data.MIMETYPE属性的内容。通过它我们可以判断当前获取数据表的列是哪种CONTENT_ITEM_TYPE。之后根据需要在对应的mimetype下,通过android.provider.ContactsContract.CommonDataKind来获取对应索引列下的内容。代码中的关键部分我都做了注释。至于android.provider.ContactsContract的用法和详细说明,请自行查找相关文档,在此不做过多介绍。

2、添加

添加的道理也是一样,根据需要通过mimetype往通讯录数据库中添加内容。内容不是很复杂,直接上代码

/** 
  * 添加新的联系人
  * @param name 名称 -- 不可为空
  * @param company 公司
  * @param position 职位
  * @param numberlist 电话列表
  * @param emaillist 邮箱列表
  * @param note 备注
  */
 public static void addContacts(Bitmap avatar, String name, String company, String position, List<AddContactsNumberItem> numberlist,
   List<AddContactsNumberItem> emaillist, String note){//AddContactsNumberItem为我自定义类,用来存放phone,email这样的存在多条记录的属性值

  ContentValues values = new ContentValues();
  // 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId
  Uri rawContactUri = EPApplication.getContextObject().getContentResolver().insert(
    RawContacts.CONTENT_URI, values);//EPApplication是我定义的Application的子类,getContextObject方法返回的是context
  long rawContactId = ContentUris.parseId(rawContactUri);
  // 表插入姓名数据
  values.clear();
  values.put(Data.RAW_CONTACT_ID, rawContactId);
  values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);// 内容类型
  values.put(StructuredName.GIVEN_NAME, name);
  EPApplication.getContextObject().getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
    values);

  //添加公司和地址
  if (company != null || position != null) {
   values.clear();
   values.put(Data.RAW_CONTACT_ID, rawContactId);
   values.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
   if(company != null){
    values.put(Organization.COMPANY, company);
   }
   if (position != null) {
    values.put(Organization.TITLE, position);
   }
   values.put(Organization.TYPE, Organization.TYPE_WORK);
   EPApplication.getContextObject().getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
     values);
  }
  
  // 插入电话数据
  if (numberlist != null && numberlist.size()>0) {
   for (AddContactsNumberItem item : numberlist) {
    int type = 0;
    if (item.getName().equals("手机")) {
     type = Phone.TYPE_MOBILE;
    } else if (item.getName().equals("工作")){
     type = Phone.TYPE_WORK;
    } else if (item.getName().equals("家庭")){
     type = Phone.TYPE_HOME;
    } else if (item.getName().equals("工作传真")){
     type = Phone.TYPE_FAX_WORK;
    } else if (item.getName().equals("家庭传真")){
     type = Phone.TYPE_FAX_HOME;
    } else if (item.getName().equals("其他")){
     type = Phone.TYPE_OTHER;
    }
    values.clear();
    values.put(Data.RAW_CONTACT_ID, rawContactId);
    values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
    values.put(Phone.NUMBER, item.getContent());
    values.put(Phone.TYPE, type);
    EPApplication.getContextObject().getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
      values);
   }
  }
  
  //添加邮箱
  if (emaillist != null && emaillist.size()>0) {
   for (AddContactsNumberItem item : emaillist) {
    int type = 0;
    if (item.name.equals("工作")) {
     type = Email.TYPE_WORK;
    } else if (item.name.equals("家庭")) {
     type = Email.TYPE_HOME;
    } else if (item.name.equals("其他")) {
     type = Email.TYPE_OTHER;
    }
    values.clear();
    values.put(Data.RAW_CONTACT_ID, rawContactId);
    values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
    values.put(Email.DATA, item.getContent());
    values.put(Email.TYPE, type);
    EPApplication.getContextObject().getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
      values);
   }
  }
  
  // 添加备注
  if (note != null && !note.isEmpty()) {
   values.clear();
   values.put(Data.RAW_CONTACT_ID, rawContactId);
   values.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
   values.put(Note.NOTE, note);
   EPApplication.getContextObject().getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
     values);
  }
  
  // 设置头像
  if (avatar != null) {
   values.clear();
   values.put(Data.RAW_CONTACT_ID, rawContactId);
   values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
   ByteArrayOutputStream array = new ByteArrayOutputStream();
   avatar.compress(Bitmap.CompressFormat.JPEG, 80, array);
   values.put(Photo.PHOTO, array.toByteArray());
   EPApplication.getContextObject().getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
     values);
  }
 }

小结

每个人对通讯录的理解都有不同,这也说明通讯录使用的灵活性。不管是通讯录还是其他的什么知识,我们都可以用方便自己的形式进行记录和理解。最近一段时间看了很多书,对IOS的开发也在继续深入中。也许正是因为开始了一门新的语言swift,所以才会让我对“吃饭的家伙”Android,有了更深和更客观的认识。如果可能的话,还是多了解一门语言吧。确实会有很多说不出的帮助和提升。也许明年会研究一下HTML5和JS吧。明天的事谁又说的准呢!

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

推荐阅读更多精彩内容