Android如何从通讯录中获取移动/工作/家庭等不同类型的联系人号码?
Android 读取不同类型联系人号码实现方案
你之前的写法仅查询了号码字段,没有获取号码类型对应的字段,且没有遍历Cursor的所有结果行,自然只能拿到单条号码、无法区分号码归属类型。
实现核心逻辑:
- 查询联系人号码表时,除了号码字段,额外把号码类型、自定义类型标签字段加入查询列
- 不要只读取Cursor的第一行数据,遍历所有行,一个联系人绑定多个号码时,会在表中对应多行记录
- 拿到每行的类型值后,和系统预置的类型常量比对,就能区分移动、工作、家庭等不同类别的号码
完整实现代码如下:
// 声明需要查询的字段集合 String[] queryColumns = new String[]{ ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.LABEL }; // 执行查询,用try-with-resources自动关闭Cursor避免内存泄漏 try (Cursor phoneCursor = getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, queryColumns, null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC" )) { if (phoneCursor == null) { return; } // 提前获取各字段的索引值,避免循环内重复查询消耗性能 int contactIdIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID); int nameIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME); int numberIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER); int typeIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE); int labelIndex = phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL); // 遍历所有结果行 while (phoneCursor.moveToNext()) { long contactId = phoneCursor.getLong(contactIdIndex); String contactName = phoneCursor.getString(nameIndex); String phoneNumber = phoneCursor.getString(numberIndex); int numberTypeCode = phoneCursor.getInt(typeIndex); String customLabel = phoneCursor.getString(labelIndex); // 匹配号码类型 String numberType; switch (numberTypeCode) { case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE: numberType = "移动号码"; // 此处编写移动号码的存储/处理逻辑 break; case ContactsContract.CommonDataKinds.Phone.TYPE_WORK: numberType = "工作号码"; // 此处编写工作号码的存储/处理逻辑 break; case ContactsContract.CommonDataKinds.Phone.TYPE_HOME: numberType = "家庭号码"; // 此处编写家庭号码的存储/处理逻辑 break; case ContactsContract.CommonDataKinds.Phone.TYPE_MAIN: numberType = "主号码"; break; case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK: numberType = "工作传真"; break; case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME: numberType = "家庭传真"; break; case ContactsContract.CommonDataKinds.Phone.TYPE_PAGER: numberType = "寻呼机号码"; break; case ContactsContract.CommonDataKinds.Phone.TYPE_OTHER: numberType = "其他号码"; break; case ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM: // 自定义类型直接读取用户设置的标签 numberType = TextUtils.isEmpty(customLabel) ? "自定义号码" : customLabel; break; default: numberType = "未知类型号码"; break; } // 可根据contactId做聚合,把同一联系人的不同类型号码归集到同一个实体对象中 } }
注意事项
- 必须在
AndroidManifest.xml中声明读联系人权限:<uses-permission android:name="android.permission.READ_CONTACTS" />,Android 6.0及以上版本需要在运行时动态申请该权限,否则查询会失败 - 不要调用
moveToFirst()后就直接取数,必须通过循环遍历所有行,才能拿到联系人绑定的全部号码 - 部分厂商定制ROM可能新增私有号码类型,通过default分支做兜底即可,不会出现类型匹配崩溃的问题
内容的提问来源于stack exchange,提问作者peerzada burhan
相关产品推荐
相关产品推荐

