android手机联系人数据库分析 推荐
2013-12-22 20:04
453 查看
最近给别人做android的项目,其中有关于手机联系人的那一块,要求查看联系人的信息(手机号码,名字,所在群组,家庭号码,家庭地址,电子邮箱,备注,公司,工作号码等)。在此分享下学习android手机联系人数据库的知识。如有遗漏和错误,望请教。
运行结果图如下:
上面是每个item对应的布局,右下角被挡住的两个分别为家庭号码,工作号码
哎,不同人信息不一样,长度也不一样啊,看起来不是很美观,
在群组中,因为所有人都在“所有联系人”组中,又在其他组中,故:查询组有多个。
还是先把核心代码贴出来
在进行一系列查询的时候应该注意一点的就是:Contacts表中_ID是唯一的,也是和其他表关联的,也就是说,得到这个Id后,其他信息都可以通过它得到。那么反过来利用其他值(如:手机号)来得到这个id后,也就可以得到其他相关的信息了。
为什么要注释掉在联系人表中的查询?
其中一个原因就是可能会有冗余的信息(某个人被删了,但他的一些信息却是存在的),这与android手机联系人数据库表设计有关。因为在删除一个人的时候,并不是直接删除了,而是做标记代替的。
出于上面的原因,所以没有从这表中开始查询。
另外在系统中有一张总表android.provider.ContactsContract.Data。在这个表里面存放着所有联系人的所有具体信息(只要设置条件可以代替其他表做查询)。
在本例中为了使联系人的信息是对应的,用HashMap来保存,contact_id作为key,将九种信息封装成类作为HashMap的value
现在分析代码中取得的九种不同信息
1、手机号表(
android.provider.ContactsContract.CommonDataKinds.Phone)
在这张表中,可以找到联系人名,以及各种号码(手机号,家庭号码,工作号码等)等
在Phone中有一个属性叫做TYPE,它是用来标识号码类型的。以上三种类型分别对应的是:
TYPE_MOBILE,TYPE_HOME, TYPE_WORK.
此时查询函数使用如下
这样就解决了四种信息(姓名,三种号码)的获取了
2、邮箱表(
android.provider.ContactsContract.CommonDataKinds.Email)
和Phone表一样,Email类也有一个TYPE属性来标识邮箱类:
TYPE_HOME,TYPE_MOBILE,TYPE_WORK.意思很直观,就不解释了。
此时查询函数使用如下:
3、组织表(android.provider.ContactsContract.CommonDataKinds.Organization)
把它叫做organization应该是有原因的吧,公司是可以看做一种组织的。与前面查询不同的是Organization类没有CONTENT_URI的属性,也就是说,不能直接查。
在Organization中可以查到的信息有公司名、职位、办公位置等。
前面说过在Data中有所有联系人相关的信息,那么此时应该查询Data,通过限制查询Organization的信息。
此时查询函数使用如下:
4、地址信息(android.provider.ContactsContract.CommonDataKinds.StructuredPostal)
在这里,可以查到所在国家,城市,街道,邮编,区域等等
在前面查询公司时,还没有说怎么查询公司所在地。
,在StructurePost中有一个字段TYPE,他对应的有以下几种类型TYPE_CUSTOM,TYPE_HOME,TYPE_WORK,TYPE_OTHER。意思很明确就不说了。
那怎么查询呢?遗憾的是StrucurePost中没有CONTENT_URI,所以我们不能直接查,所幸的是我们又可以利用Data来查询。如下查询家庭地址
其他对应关系请看android 开发文档啊
5、备注(android.provider.ContactsContract.CommonDataKinds.Note)
也是利用Data查询
6、联系人所在群组查询稍微麻烦一点点啦
android.provider.ContactsContract.Groups
android.provider.ContactsContract.CommonDataKinds.GroupMembership
在Groups中存放的是手机系统当前的所有分组信息。
GroupMembership中关联了联系人所在群组。
第一步:应该取出当前手机中的所有分组信息
第二步:通过Data查询Groupmembership的信息
故:在查询分组信息时,用了两个临时List来存放Groups信息
ok了,所有查询可以完美解决啦。
哈哈!!!通过这次实践对android手机联系人数据库有一定了解了。
A:每个联系人信息都被唯一的一个contact_id来标识
B:大表(Data)细分为小表(Phone等)
C:数据块化(Note,StrucuredPostal等)
D:数据类型化(Phone的几种类,Email的几种类型等等)
个人觉得掌握这几点就可以查出android手机联系人中所有联系人具体信息了。当然,这些信息你在添加联系人的时候要添加了才有,不然还是null
在分析中也阐述了查询其他信息的做法,希望对大家有用!!!
附件:http://down.51cto.com/data/2363907
运行结果图如下:
上面是每个item对应的布局,右下角被挡住的两个分别为家庭号码,工作号码
哎,不同人信息不一样,长度也不一样啊,看起来不是很美观,
在群组中,因为所有人都在“所有联系人”组中,又在其他组中,故:查询组有多个。
还是先把核心代码贴出来
private void getData(){ HashMap<String, Item> list = new HashMap<String, Item>(100); /*Cursor c = getContentResolver().query(Contacts.CONTENT_URI, new String[]{Contacts._ID}, null, null, null); if(c.moveToFirst()){ int id = c.getColumnIndex(Contacts._ID); }*/ // 姓名和手机号 Cursor c = getContentResolver().query(Phone.CONTENT_URI, new String[]{Phone.DISPLAY_NAME, Phone.NUMBER, Phone.CONTACT_ID}, Phone.TYPE + "=?", new String[]{Phone.TYPE_MOBILE+""}, null); if(c.moveToFirst()){ int id = c.getColumnIndex(Phone.CONTACT_ID); int name = c.getColumnIndex(Phone.DISPLAY_NAME); int num = c.getColumnIndex(Phone.NUMBER); do{ String cid = c.getString(id); String cname = c.getString(name); String cnum = c.getString(num); Item remark = list.get(cid); if(remark == null){ remark = new Item(); list.put(cid, remark); } remark.name = cname; remark.number = cnum; Log.i(TAG, "name:" + cname + " num:" + cnum); }while(c.moveToNext()); } c.close(); // 邮箱信息 c = getContentResolver().query(Email.CONTENT_URI, new String[]{Email.DATA, Email.CONTACT_ID}, null, null, Email.CONTACT_ID + " asc"); if(c.moveToFirst()){ int id = c.getColumnIndex(Email.CONTACT_ID); int em = c.getColumnIndex(Email.DATA); do{ String cid = c.getString(id); String email = c.getString(em); Item remark = list.get(cid); if(remark == null){ remark = new Item(); list.put(cid, remark); } remark.email = email; Log.i(TAG, "email:" + email); }while(c.moveToNext()); } c.close(); Log.i(TAG, "start 工作号码"); // 工作号码 String[] projection = new String[] { Phone.NUMBER, Phone.CONTACT_ID}; c = getContentResolver().query( Phone.CONTENT_URI, projection, Phone.TYPE + "=?", new String[]{Phone.TYPE_WORK + ""}, Phone.CONTACT_ID + " asc"); if(c.moveToFirst()){ int num = c.getColumnIndex(Phone.NUMBER); int id = c.getColumnIndex(Phone.CONTACT_ID); do{ String cid = c.getString(id); String phone = c.getString(num); Item remark = list.get(cid); if(remark == null){ remark = new Item(); list.put(cid, remark); } remark.workTel = phone; Log.i(TAG, "workTel:" + phone); }while(c.moveToNext()); } c.close(); // 公司名字 c = getContentResolver().query( Data.CONTENT_URI, new String[]{Data.DATA1, Data.CONTACT_ID}, Data.MIMETYPE + "=?", new String[]{Organization.CONTENT_ITEM_TYPE}, Data.CONTACT_ID + " asc"); if(c.moveToFirst()){ int data1 = c.getColumnIndex(Data.DATA1); int id = c.getColumnIndex(Data.CONTACT_ID); do{ String cid = c.getString(id); String companyname = c.getString(data1); Item remark = list.get(cid); if(remark == null){ remark = new Item(); list.put(cid, remark); } remark.company = companyname; Log.i(TAG, "company:" + companyname); }while(c.moveToNext()); } c.close(); c = null; // 家庭住址信息 projection = new String[] { Data.DATA7, Data.DATA10, Data.DATA4, Data.CONTACT_ID }; c = getContentResolver().query( Data.CONTENT_URI, projection, Data.MIMETYPE + "=? and " + StructuredPostal.TYPE + "=?" , new String[]{StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE_HOME+""}, Data.CONTACT_ID + " asc"); if(c.moveToFirst()){ int data4 = c.getColumnIndex(Data.DATA4); int data7 = c.getColumnIndex(Data.DATA7); int data10 = c.getColumnIndex(Data.DATA10); int id = c.getColumnIndex(Data.CONTACT_ID); do{ String sData4 = c.getString(data4); String sData7 = c.getString(data7); String sData10 = c.getString(data10); String cid = c.getString(id); StringBuilder sb = new StringBuilder(); // 依次为国家、城市、街道 if(!TextUtils.isEmpty(sData10)) sb.append(sData10).append(";"); if(!TextUtils.isEmpty(sData7)) sb.append(sData7).append(";"); if(!TextUtils.isEmpty(sData4)) sb.append(sData4); Item remark = list.get(cid); if(remark == null){ remark = new Item(); list.put(cid, remark); } remark.address = sb.toString(); Log.i(TAG, "address:" + remark.address); }while(c.moveToNext()); } c.close(); // 家庭号码 projection = new String[] { Phone.NUMBER, Phone.CONTACT_ID}; c = getContentResolver().query( Phone.CONTENT_URI, projection, Phone.TYPE + "=?", new String[]{Phone.TYPE_HOME + ""}, Phone.CONTACT_ID + " asc"); if(c.moveToFirst()){ int num = c.getColumnIndex(Phone.NUMBER); int id = c.getColumnIndex(Phone.CONTACT_ID); do{ String cid = c.getString(id); String phone = c.getString(num); Item remark = list.get(cid); if(remark == null){ remark = new Item(); list.put(cid, remark); } remark.fnumber = phone; Log.i(TAG, "family Phone:" + phone); }while(c.moveToNext()); } c.close(); // 备注 projection = new String[] { Data.DATA1, Data.CONTACT_ID}; c = getContentResolver().query( Data.CONTENT_URI, projection, Data.MIMETYPE + "=?", new String[]{Note.CONTENT_ITEM_TYPE}, Data.CONTACT_ID + " asc"); if(c.moveToFirst()){ int data1 = c.getColumnIndex(Data.DATA1); int id = c.getColumnIndex(Data.CONTACT_ID); do{ String cid = c.getString(id); String note = c.getString(data1); Item remark = list.get(cid); if(remark == null){ remark = new Item(); list.put(cid, remark); } if(!TextUtils.isEmpty(note)){ remark.note = note; Log.i(TAG, "note:" + note); } }while(c.moveToNext()); } c.close(); // 对应的分组 ArrayList<String> gid = new ArrayList<String>(); // group Id ArrayList<String> gname = new ArrayList<String>(); // group name c = getContentResolver().query(Groups.CONTENT_URI, new String[]{Groups.TITLE, Groups._ID}, null, null, null); if(c.moveToFirst()){ int cc1 = c.getColumnIndex(Groups._ID); int cc2 = c.getColumnIndex(Groups.TITLE); do{ String id = c.getString(cc1); String ti = c.getString(cc2); gid.add(id); gname.add(ti); Log.i(TAG, ti); }while(c.moveToNext()); } c.close(); int len = gid.size(); /// 总共有多少个群组 c = getContentResolver().query(Data.CONTENT_URI, new String[]{GroupMembership.CONTACT_ID, GroupMembership.GROUP_ROW_ID}, Data.MIMETYPE + "=?", new String[]{GroupMembership.CONTENT_ITEM_TYPE}, null); if(c.moveToFirst()){ int cc1 = c.getColumnIndex(GroupMembership.CONTACT_ID); int cc2 = c.getColumnIndex(GroupMembership.GROUP_ROW_ID);// group ID do{ String id = c.getString(cc1); String groupId = c.getString(cc2); Item remark = list.get(id); if(remark == null){ remark = new Item(); list.put(id, remark); } for(int i = 0; i < len; i++){ if(gid.get(i).equals(groupId)){ remark.group += gname.get(i)+" ";// 一个人可能有多个群组 } } }while(c.moveToNext()); } c.close(); gid = null; gname = null; Log.i(TAG, "end"); if(data.list.size() == 0) data.list.clear(); Collection<Item> vs = list.values(); for(Item it : vs) data.list.add(it); Log.i(TAG, "size" + data.list.size()); }
class ViewHolder { TextView name, note; TextView number, address; TextView group, company; TextView email, workTel; TextView fnumber; } class Item { String name; // 姓名 String number; // 电话号码 String group=""; // 群组 String note; // 备注 String address; // 家庭地址 String fnumber; // 家庭号码 String company; // 所在公司 String workTel; // 工作号码 String email; // 邮箱 }group = "" ,是因为某些人可能属于多个分组,为了在拼接字符串时不会有null所以赋予""
在进行一系列查询的时候应该注意一点的就是:Contacts表中_ID是唯一的,也是和其他表关联的,也就是说,得到这个Id后,其他信息都可以通过它得到。那么反过来利用其他值(如:手机号)来得到这个id后,也就可以得到其他相关的信息了。
为什么要注释掉在联系人表中的查询?
其中一个原因就是可能会有冗余的信息(某个人被删了,但他的一些信息却是存在的),这与android手机联系人数据库表设计有关。因为在删除一个人的时候,并不是直接删除了,而是做标记代替的。
出于上面的原因,所以没有从这表中开始查询。
另外在系统中有一张总表android.provider.ContactsContract.Data。在这个表里面存放着所有联系人的所有具体信息(只要设置条件可以代替其他表做查询)。
在本例中为了使联系人的信息是对应的,用HashMap来保存,contact_id作为key,将九种信息封装成类作为HashMap的value
现在分析代码中取得的九种不同信息
1、手机号表(
android.provider.ContactsContract.CommonDataKinds.Phone)
在这张表中,可以找到联系人名,以及各种号码(手机号,家庭号码,工作号码等)等
在Phone中有一个属性叫做TYPE,它是用来标识号码类型的。以上三种类型分别对应的是:
TYPE_MOBILE,TYPE_HOME, TYPE_WORK.
此时查询函数使用如下
Cursor c = getContentResolver().query(Phone.CONTENT_URI, new String[]{Phone.DISPLAY_NAME, Phone.NUMBER, Phone.CONTACT_ID}, Phone.TYPE + "=?", new String[]{Phone.TYPE_MOBILE+""}, null);在where语句中用到了TYPE来限制取的是哪一种类型的号码。同理可以取得家庭号码和工作号码。
这样就解决了四种信息(姓名,三种号码)的获取了
2、邮箱表(
android.provider.ContactsContract.CommonDataKinds.Email)
和Phone表一样,Email类也有一个TYPE属性来标识邮箱类:
TYPE_HOME,TYPE_MOBILE,TYPE_WORK.意思很直观,就不解释了。
此时查询函数使用如下:
getContentResolver().query(Email.CONTENT_URI, new String[]{Email.DATA, Email.CONTACT_ID}, null, null, null);在代码中,我没有去区分到底是什么类型的邮箱。如果要区分,就在where中用type限制吧。
3、组织表(android.provider.ContactsContract.CommonDataKinds.Organization)
把它叫做organization应该是有原因的吧,公司是可以看做一种组织的。与前面查询不同的是Organization类没有CONTENT_URI的属性,也就是说,不能直接查。
在Organization中可以查到的信息有公司名、职位、办公位置等。
前面说过在Data中有所有联系人相关的信息,那么此时应该查询Data,通过限制查询Organization的信息。
此时查询函数使用如下:
getContentResolver().query( Data.CONTENT_URI, new String[]{Data.DATA1, Data.CONTACT_ID}, Data.MIMETYPE + "=?", new String[]{Organization.CONTENT_ITEM_TYPE},null);在查询映射字段中Data.DATA1其实对应的就是Organization中的COMPANY。所以换成Organization.COMPANY也可以。至于这些对应关系可以在android开发文档中查看。
4、地址信息(android.provider.ContactsContract.CommonDataKinds.StructuredPostal)
在这里,可以查到所在国家,城市,街道,邮编,区域等等
在前面查询公司时,还没有说怎么查询公司所在地。
,在StructurePost中有一个字段TYPE,他对应的有以下几种类型TYPE_CUSTOM,TYPE_HOME,TYPE_WORK,TYPE_OTHER。意思很明确就不说了。
那怎么查询呢?遗憾的是StrucurePost中没有CONTENT_URI,所以我们不能直接查,所幸的是我们又可以利用Data来查询。如下查询家庭地址
projection = new String[] { Data.DATA7, Data.DATA10, Data.DATA4, Data.CONTACT_ID }; c = getContentResolver().query( Data.CONTENT_URI, projection, Data.MIMETYPE + "=? and " + StructuredPostal.TYPE + "=?" , new String[]{StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE_HOME+""}, null);DATA10,DATA7,DATA4分别对应国家,城市,街道(对应的COUNTRY,CITY,STREET)
其他对应关系请看android 开发文档啊
5、备注(android.provider.ContactsContract.CommonDataKinds.Note)
也是利用Data查询
projection = new String[] { Data.DATA1, Data.CONTACT_ID}; c = getContentResolver().query( Data.CONTENT_URI, projection, Data.MIMETYPE + "=?", new String[]{Note.CONTENT_ITEM_TYPE}, null);
6、联系人所在群组查询稍微麻烦一点点啦
android.provider.ContactsContract.Groups
android.provider.ContactsContract.CommonDataKinds.GroupMembership
在Groups中存放的是手机系统当前的所有分组信息。
GroupMembership中关联了联系人所在群组。
第一步:应该取出当前手机中的所有分组信息
c = getContentResolver().query(Groups.CONTENT_URI, new String[]{Groups.TITLE, Groups._ID}, null, null, null);通过GroupMembership.GROUP_ROW_ID关联到Groups._ID
第二步:通过Data查询Groupmembership的信息
getContentResolver().query(Data.CONTENT_URI, new String[]{GroupMembership.CONTACT_ID, GroupMembership.GROUP_ROW_ID}, Data.MIMETYPE + "=?", new String[]{GroupMembership.CONTENT_ITEM_TYPE}, null);
故:在查询分组信息时,用了两个临时List来存放Groups信息
ok了,所有查询可以完美解决啦。
哈哈!!!通过这次实践对android手机联系人数据库有一定了解了。
A:每个联系人信息都被唯一的一个contact_id来标识
B:大表(Data)细分为小表(Phone等)
C:数据块化(Note,StrucuredPostal等)
D:数据类型化(Phone的几种类,Email的几种类型等等)
个人觉得掌握这几点就可以查出android手机联系人中所有联系人具体信息了。当然,这些信息你在添加联系人的时候要添加了才有,不然还是null
在分析中也阐述了查询其他信息的做法,希望对大家有用!!!
附件:http://down.51cto.com/data/2363907
相关文章推荐
- Android手机联系人数据库分析
- Android通过查询数据库手机联系人信息
- Android学习(六)导出模拟器/手机联系人数据库到PC指定目录
- Android学习(六)导出模拟器/手机联系人数据库到PC指定目录
- android如何获取手机联系人的数据库
- Android 联系人数据库链接关系分析
- SQLiteStudio优雅调试Android手机数据库Sqlite(推荐)
- android查询数据库获得手机里面所有的联系人
- Android学习(六)导出模拟器/手机联系人数据库到PC指定目录
- Android调用系统选择联系人,适合更多种手机,Google官方推荐
- android如何获取手机联系人的数据库示例代码
- android Qwerty 键盘搜索联系人分析与实现(支持多音字)
- [智能手机取证系列] Android手机逻辑数据提取和分析
- Android获取联系人信息[名字,手机,电话,公司名称,昵称]
- Android手机游戏:外星飞人(推荐)
- 从手机来电分析android消息机制
- Android 获取手机联系人实例代码详解
- Android 联系人数据库表详解
- 通过读数据库来获取手机联系人
- Android界面编程之QuickContactBadge(一幅图片关联到手机上的一个联系人)