Android 通过手机号查询通讯录联系人姓名字段索引返回-1如何解决
问题排查与解决方案
核心问题原因
字段索引返回-1的问题,核心原因如下:
- 使用的查询URI不支持拆分姓名字段:
ContactsContract.PhoneLookup.CONTENT_FILTER_URI是系统提供的快速通过手机号匹配联系人的接口,它返回的结果集仅包含_ID、DISPLAY_NAME、手机号、头像ID这类基础信息,本身就不包含GIVEN_NAME(名)、FAMILY_NAME(姓)这类拆分的结构化姓名字段,所以查询这两个字段的索引必然返回-1。 - 代码存在两处可导致异常的写法:
- 定义的存储查询URI的变量是
contactUri,但调用query方法时传入的第一个参数是未定义的uri,会导致查询请求错误 - 遍历Cursor的循环中没有调用
moveToNext()方法,会导致无限死循环
- 定义的存储查询URI的变量是
正确实现逻辑
要获取拆分的姓名字段,需要分两步查询:
- 先通过PhoneLookup接口用手机号查到对应的联系人ID
- 用联系人ID去查询系统通讯录的Data表,筛选结构化姓名类型的数据,即可拿到拆分的姓和名
修正后的代码示例
// 第一步:通过手机号查询联系人ID Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber)); Cursor phoneCursor = cResolver.query(contactUri, null, null, null, null); if(phoneCursor != null && phoneCursor.moveToFirst()) { int idColumnIndex = phoneCursor.getColumnIndex(ContactsContract.Contacts._ID); while (!phoneCursor.isAfterLast()) { long contactId = phoneCursor.getLong(idColumnIndex); MyContact contact = new MyContact(); contact.setId(contactId); // 第二步:用联系人ID查询结构化姓名数据 Cursor nameCursor = cResolver.query( ContactsContract.Data.CONTENT_URI, new String[]{ ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME }, ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?", new String[]{ String.valueOf(contactId), ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE }, null ); if(nameCursor != null && nameCursor.moveToFirst()) { int firstNameIndex = nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME); int lastNameIndex = nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME); contact.setFirstName(nameCursor.getString(firstNameIndex)); contact.setLastName(nameCursor.getString(lastNameIndex)); nameCursor.close(); } // 此处处理得到的contact对象 phoneCursor.moveToNext(); } phoneCursor.close(); }
额外注意事项
- 请确保你的应用已经申请了
android.permission.READ_CONTACTS权限,Android 6.0及以上版本需要动态申请这个危险权限 - 部分联系人可能没有填写拆分的姓名字段,此时读取到的值会为null,建议做好空值兼容处理
内容的提问来源于stack exchange,提问作者testivanivan
相关产品推荐
相关产品推荐

