`

Android通讯录查询篇--ContactsContract.Data 二

 
阅读更多

上次说Data.MIMETYPE这个玩意很重要,官方的文档中描述了一大段的话。里面比较重要的几点是:

1、在Data中有一大段的公共数据段,DATA1~DATA15。这名子咋一看,真搞笑,哪有这样为数据命名的,神也记不住是干什么的的啊!

2、上面说的那些公共数据段所存的数据类型是由这个MIMETYPE决定的。

虽说这两个重要,不过刚看到这里,我还是懵了,这到底是个什么玩意嘛。(当然这很有可能是因为英文水平差,没看完全懂的原因。)

再看看官方文档,上面有个例子说,如果MIMETYPE的值是Phone.CONTENT_ITEM_TYPE,则DATA1就是电话号码,如果MIMETYPE的值是Email.CONTENT_ITEM_TYPE则DATA1的值就是E-mail地址。这样一说,又似乎明白了点。(还是举实例子来的实在!)

  在上次说的那个官方代码里面不就有将MIMETYPE赋值为Phone.CONTENT_ITEM_TYPE的么。所以那个查询就用来查电话了。

  在MIMETYPE的描述里面说,它可以被赋许多值:

  StructuredName.CONTENT_ITEM_TYPE

  Phone.CONTENT_ITEM_TYPE

  Email.CONTENT_ITEM_TYPE

  Photo.CONTENT_ITEM_TYPE

  Organization.CONTENT_ITEM_TYPE

  Im.CONTENT_ITEM_TYPE

  Nickname.CONTENT_ITEM_TYPE

  Note.CONTENT_ITEM_TYPE

  StructuredPostal.CONTENT_ITEM_TYPE

  GroupMembership.CONTENT_ITEM_TYPE

  Website.CONTENT_ITEM_TYPE

  Event.CONTENT_ITEM_TYPE

  Relation.CONTENT_ITEM_TYPE

  现在我们知道的有用Phone那个可以查电话,那用哪个查姓名呢?

  再之后看文档时候可以明白把StructuredName.CONTENT_ITEM_TYPE给MINETYPE就行了。(但刚开始的时候可能是因为看英文,怎么都没把它们好的联系起来。)

  所将官方的代码改成这样的话就可以查询姓名了。

1 Cursor c = getContentResolver().query(Data.CONTENT_URI,
2 new String[]{Data._ID,StructuredName.DISPLAY_NAME, },
3 Data.MIMETYPE + "='" + StructuredName.CONTENT_ITEM_TYPE + "'",
4 null, null);

  其中游标C的结果的第二个字段(StructuredName.DISPLAY_NAME)就是姓名,准确的说应该是“显示姓名”(因为姓名也以再细分为姓和名)。

如果还没有理解的话,也不要紧,之后我会把它讲的形像一点。

  通讯录虽然不是一个什么难的东西,不过我想还是理顺一点好,免得过些天后又晕了。。

这次主要要做的就是根据姓名来查找电话,并且加强对通讯录的理解。

  以前做一些用到数据库的东西的时候,可能光看代码也是不好联系起各个数据之间的关系,所以我先想到的还是数据库。幸运的是,它还真是一个数据库。

  Android里面内置的是SQLite的数据库,虽然对数据库不怎么了解,但关系型数据库,基本操作也就那些,而且基本都一样,所以就直接用呗。

用命令行下的adb shell进入Android的模拟器,进入data/data目录下面,这里面就是安装的一些应用程序。找啊找,里面有一个com.android.providers.contacts,怎么看都是一个通讯录相关的程序,进入这个目录下,里面有一个databases,就它了,再进去就可以看到有个contacts2.db的文件。

  用sqlite3打开这个数据库文件。查看里面的表。里面表很多,不过看两遍后发现表的名字很熟悉,像什么data,raw_contacts,contacts,minetypes等,前面几个都是我们上次说的那几个所谓的数据模型,它们还真是数据库。

  

  查询一下data表里面的所有信息,可以发现里面的信息联系起来就都是我们通讯录里面的名片。虽然不是一条显示全部,但每个名字每个电话,每个E-mail都有,而且都是分开显示的。现在对于这个应该就有点感觉了。

  

  再看一下表的结构,用”.schema” 命令后会看到,类似如下的信息:

.schema data

CREATE TABLE data (

_id INTEGER PRIMARY KEY AUTOINCREMENT,

package_id INTEGER REFERENCES package(_id),

mimetype_id INTEGER REFERENCES mimetype(_id) NOT NULL,

raw_contact_idINTEGER REFERENCES raw_contacts(_id) NOT NULL,

is_primary INTEGER NOT NULL DEFAULT 0,

is_super_primary INTEGER NOT NULL DEFAULT 0,

data_version INTEGER NOT NULL DEFAULT 0,

data1 TEXT,

data2 TEXT,

data3 TEXT,

data4 TEXT,

data5 TEXT,

data6 TEXT,

data7 TEXT,

data8 TEXT,

data9 TEXT,

data10 TEXT,

data11 TEXT,

data12 TEXT,

data13 TEXT,

data14 TEXT,

data15 TEXT,

data_sync1 TEXT,

data_sync2 TEXT,

data_sync3 TEXT,

data_sync4 TEXT );

  下面还有点索引和触发器的信息就不看了,结合查询的数据看一下。其中“_id”就是表的一个自增id字段。第二个package_id暂时没用到,数据里面全是空。第三个字段minetype_id应该就是MIMETYPE了(其实还是有点不一样的)。后的raw_contact_id就是名片的ID。再看后的data1,data2等字段,每条数据中的这几项都不大相同,准确的说,minetype_id字段不同的数据data1,data2等字段的数据就不同。

  现在应该就有一个概念了,以前说的MIMETYPE的值确定Data.DATA1等的值的类型的意思就是在data数据库中通过mimetype_id的值就可以确定data1,data2等字段的真正意义。也就是说在data数据库中通过minetype_id的值可以确定那一条数据到底是存储的姓名,还是电话,还是E-mail或者其它。

  这样一来,如果我们要查询某个特定的数据的时候就可以直接查询data表里面的data1,data2这类字段的值,而唯一的必要条件就是在where条件语句里面将minetype_id赋为对应的值。这样就有了一个统一的数据访问方法。而且可以通过这个表查到所以想要的数据。

  所以如果想要通过姓名查找一个人的电话就可以这样了,先通过设置MIMETYPE 为

  ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME ,查找姓名所对应的RAW_CONTACT_ID 。再将MIMETYPE 设置为

  ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,查找上面找到的RAW_CONTACT_ID 所对应的电话就可以了。

  按这个细路就可以写代码了:

01    /**
02 * 通过姓名(uName)来查找通讯录,返回一个list。 其中"display_name"保存姓名,"phone_number"保存电话
03 */
04 public List<HashMap<String, String>> getContactsByName(String uName) {
05 List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
06 boolean isQueryAll = false;
07 // cu姓名游标,cn电话号码游标
08 Cursor cu, cn = null;
09 // 查询条件,SQL是的Where语句的后部分
10 String selection = null;
11
12 uName = uName.trim();
13 // 是否查询全部通讯录,如果姓名为空则是
14 isQueryAll = uName.equals("") ? true : false;
15
16 if (isQueryAll) {
17 // 查询全部时的,查询条件,主要用在cu游标上
18 selection = ContactsContract.Data.MIMETYPE
19 + "='"
20 + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
21 + "'";
22 //System.out.println("Query For ALl--" + selection);
23 } else {
24 // 根据姓名查询时的,查询条件,主要用在cu游标上
25 selection = ContactsContract.Data.MIMETYPE
26 + "='"
27 + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
28 + "'"
29 + " AND "
30 + ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME
31 + " LIKE " + "'%" + uName + "%'";
32 //System.out.println("Query For Some--" + selection);
33 }
34
35 try {
36 // 根据姓名查询出完整姓名和通讯录ID
37 cu = contentReso
38 .query(
39 URI,
40 new String[] {
41 ContactsContract.Data.RAW_CONTACT_ID,
42 ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME },
43 selection, null, null);
44 // 根据通讯录ID,查找对应的电话号码的查询条件,主要用于cn游标
45 selection = ContactsContract.Data.MIMETYPE + "='"
46 + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
47 + "'"
48 + " AND "
49 + ContactsContract.Data.RAW_CONTACT_ID
50 + "=?";
51 //System.out.println("Number Query--" + selection);
52 while (cu.moveToNext()) {
53 String contactId = String.valueOf(cu.getInt(0));
54 // 开始查找电话号码
55 //System.out.println(" Start Query Num");
56 cn = contentReso
57 .query(
58 URI,
59 new String[] { ContactsContract.CommonDataKinds.Phone.NUMBER },
60 selection, new String[] { contactId }, null);
61
62 while (cn.moveToNext()) {
63 // 将一组通讯录记录在HashMap中
64 HashMap<String, String> map = new HashMap<String, String>();
65 map.put("display_name", cu.getString(1));
66 map.put("phone_number", cn.getString(0));
67 // 将查到通讯录添加到List中
68 list.add(map);
69 }
70 }
71 //关闭游标
72 cu.close();
73 cn.close();
74 } catch (Exception e) {
75 // TODO: handle exception
76 }
77 return list;
78 }
79 }

PS:

  最后再说一下那个MIMETYPE ,在data数据库里面它的值是整型,如果看一下官方文档的话,给它所赋的值像

  ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME 之类的都字符串,那么这些字符串和data里面的整型是怎么对应的呢。

  其实就是通过mimetypes表来对应的。里面的对应列主要就是9个 :

  1|vnd.android.cursor.item/email_v2

  2|vnd.android.cursor.item/im

  3|vnd.android.cursor.item/postal-address_v2

  4|vnd.android.cursor.item/photo

  5|vnd.android.cursor.item/phone_v2

  6|vnd.android.cursor.item/name

  7|vnd.android.cursor.item/organization

  8|vnd.android.cursor.item/nickname

  9|vnd.android.cursor.item/group_membership

分享到:
评论

相关推荐

    android 通讯录

    总之,Android通讯录功能的实现涉及多个方面,包括权限管理、Content Provider、数据查询与操作、UI交互以及同步机制。通过学习和分析提供的源代码,你可以深入了解这些概念,并应用于自己的项目中。

    android访问通讯录中的联系人和添加联系人

    在Android系统中,访问和管理通讯录是常见的功能需求,涉及到Android框架中对联系人数据的API使用。本文将深入探讨如何在Android应用中实现访问通讯录中的联系人以及添加新联系人的步骤。 首先,我们需要了解...

    ANDROID通讯录代码

    本资源专注于Android通讯录的编程实践,旨在帮助开发者了解如何在Android应用中实现与系统通讯录的交互。下面我们将深入探讨相关知识点。 1. **Android权限管理**:在访问通讯录之前,你需要在AndroidManifest.xml...

    使用android通讯录中的内容提供者实例

    二、Android通讯录内容提供者 Android系统的通讯录内容提供者是ContactsProvider,它管理着手机上的所有联系人数据。主要包含两个表:Contacts表和Data表。Contacts表存储联系人的基本信息,如姓名、ID等,而Data表...

    Android高级应用源码-Android手机的通讯录联系人信息.zip

    本资源“Android高级应用源码-Android手机的通讯录联系人信息.zip”提供了深入理解和操作Android通讯录功能的实践示例。以下是基于这个主题的详细知识点讲解: 1. **Android权限管理**: 在访问或修改手机通讯录...

    Android通讯录读取,插入,删除,更新

    综上所述,Android平台上的通讯录操作涵盖了权限管理、查询、插入、更新和删除等多个方面。了解并熟练掌握这些知识点对于Android开发者来说是必不可少的,特别是在开发涉及个人数据管理的应用时。通过实践,你可以更...

    Android代码-Android手机的通讯录联系人信息.zip

    对于更详细的联系人信息,如电话号码或电子邮件,我们需要查询`ContactsContract.Data`表,并使用`contactId`作为过滤条件。例如,获取联系人的电话号码: ```java Uri phoneUri = Uri.withAppendedPath...

    android通讯录

    在Android系统中,通讯录(Contacts)是...总结,Android通讯录开发涉及到权限管理、数据查询、信息解析、数据操作以及各种开发工具的使用。通过理解并熟练运用这些知识点,开发者能够构建出功能完善的通讯录管理应用。

    安卓Android源码——获取手机通讯录的实战应用(含SIM卡中的联系人).rar

    8. **分组和标签**:Android通讯录还支持联系人分组和标签,可以通过`ContactsContract.Groups`和`ContactsContract.Labels`表进行管理。 9. **异步查询**:考虑到性能和用户体验,建议在主线程之外进行通讯录查询...

    Android通讯录分组更新

    Android通讯录的分组管理是通过Content Provider接口实现的,涉及对`ContactsContract.Groups`和`ContactsContract.CommonDataKinds.GroupMembership`表的操作。正确理解和使用这些API,可以轻松实现通讯录的分组...

    安卓通讯录联系人打电话归属地相关-把所有手机联系人导出到一个vcf文件中。里面包含android-vcard包.rar

    String email = detailCursor.getString(detailCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)); vcfWriter.writeEmail(name, email, VCardType.WORK); } } detailCursor.close(); } ...

    Android 获取通讯录程序源码.zip

    通过`ContactsContract.Data`表查询具体字段,如`ContactsContract.CommonDataKinds.Phone.TYPE`获取电话类型(手机、家庭等),`ContactsContract.CommonDataKinds.Email.TYPE`获取邮箱类型。 6. **UI展示**: 将...

    Android 获取通讯录程序源码.rar

    要访问通讯录,我们主要与`ContactsContract`类交互,它是Android提供的一个常量类,定义了访问联系人数据的各种URI和列名。 **1. 获取读取通讯录权限** 在Android 6.0及以上版本,需要在运行时动态申请权限。在...

    android操作手机通讯录增伤改查

    总结来说,Android中的手机通讯录操作主要依赖`ContactsContract`类,通过ContentResolver进行CRUD操作。在实际开发中,应充分考虑性能、用户体验以及权限管理,以实现稳定、高效的通讯录功能。`ContactsDemo`项目...

    Android读取通讯录中设置邮件的联系人

    综上所述,实现"Android读取通讯录中设置邮件的联系人"的功能涉及到Android的权限管理、ContentResolver、ContactsContract API的使用,以及数据处理和性能优化等多个方面。通过合理的编程实践,可以创建一个高效且...

    android 通讯录 (有索引)

    总之,Android的通讯录操作是一个综合了数据查询、权限管理、UI设计和用户交互的复杂过程。掌握这些知识点,开发者就能为用户提供高效且易用的通讯录管理功能。在实际开发中,还需要考虑性能优化、隐私保护以及不同...

    安卓页面跳转通讯录添加

    例如,对于旧版本的Android,你可能需要使用ContactsContract.Data._ID来代替ContactsContract.Data.RAW_CONTACT_ID。 最后,记得在Eclipse中运行你的应用程序,并在模拟器或真实设备上测试页面跳转和添加联系人的...

    安卓开发-Android手机的通讯录联系人信息.zip.zip

    - **电子邮件地址**:同样,电子邮件信息在另一张表中,使用`ContactsContract.CommonDataKinds.Email`类的URI查询,`DATA`列存储邮件地址。 6. **插入联系人**: 使用ContentResolver的`insert()`方法插入新的...

    android源码

    在Android开发中,将数据从TXT文件导入到手机通讯录是一项常见的任务,这对于数据迁移、备份或应用集成非常有用。本教程将详细讲解如何通过源码实现这一功能,旨在帮助初学者理解Android与文件系统以及联系人API的...

Global site tag (gtag.js) - Google Analytics