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就行了。(但刚开始的时候可能是因为看英文,怎么都没把它们好的联系起来。)

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

 

1Cursor 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
http://blog.csdn.net/xiaoxiao108/article/details/6901964 最近想写段android程序玩玩。 开发环境 eclipse ,android2.2 开发环境搭建 1.先安装jdk 2.下载安装eclipse 3.下载安装android sdk 4.安装eclipse插件 adt 5.配置 Window > Preferences 中的android sdk路径 6.创建 AVD 实现方法很简单 1.把通讯录中的联系人,电话号码保存到txt文件中完成备份。 2.读取txt文件,导入到通讯录完成还原。 具体代码 1.添加 通讯录读写权限,存储卡写权限 2.写文件代码 File saveFile=new File("/sdcard/test.txt"); FileOutputStream outStream; try { outStream = new FileOutputStream(saveFile); outStream.write(str.getBytes()); outStream.close(); } catch (Exception e) { setTitle(e.toString()); } 3.取通讯录联系人 str=""; Cursor cur = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if (cur.moveToFirst()) { int idColumn = cur.getColumnIndex(ContactsContract.Contacts._ID); int displayNameColumn = cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); do { String contactId = cur.getString(idColumn); String disPlayName = cur.getString(displayNameColumn); str+=disPlayName; int phoneCount = cur.getInt(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)); if(phoneCount>0){ Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID+ " = " + contactId, null, null); int i=0; String phoneNumber; if(phones.moveToFirst()){ do{ i++; phoneNumber= phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phon
这个错误的原因是您在插入联系人记录时,使用了错误的URI。在Android系统中,联系人记录分为两种类型:单个联系人记录和聚合联系人记录。单个联系人记录对应的URI为`ContactsContract.RawContacts.CONTENT_URI`,而聚合联系人记录对应的URI为`ContactsContract.Contacts.CONTENT_URI`。在您的代码中,应该使用`ContactsContract.RawContacts.CONTENT_URI`来插入单个联系人记录,而不是使用`ContactsContract.Contacts.CONTENT_URI`。 另外,您在添加联系人电话号码和邮箱地址时,使用了错误的字段名。正确的字段名应该是`ContactsContract.CommonDataKinds.Phone.NUMBER`和`ContactsContract.CommonDataKinds.Email.ADDRESS`。 修改后的代码如下所示: ```kotlin private fun exportToApp() { thread { var count = 0 for (contacti in contactList) { if (contacti.isChecked) { val contentResolver = getContentResolver() val contact = ContentValues().apply { put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contacti.name) } val uri: Uri? = contentResolver.insert(ContactsContract.RawContacts.CONTENT_URI, contact) val rawContactId = uri?.lastPathSegment val phone = ContentValues().apply { put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) put(ContactsContract.CommonDataKinds.Phone.NUMBER, contacti.phone) } contentResolver.insert(ContactsContract.Data.CONTENT_URI, phone) val email = ContentValues().apply { put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) put(ContactsContract.CommonDataKinds.Email.ADDRESS, contacti.email) } contentResolver.insert(ContactsContract.Data.CONTENT_URI, email) count++ } } runOnUiThread { Toast.makeText(this,"已导出${count}位联系人!",Toast.LENGTH_LONG).show() } } finish() } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值