如何从Android联系人内容提供器获取无重复的手机号联系人
解决Android联系人获取时手机号重复的问题
我明白你现在的困扰——已经成功获取到带手机号的联系人数据,但同一个手机号会重复出现两次。这种情况在Android联系人操作里挺常见的,咱们一步步来搞定它。
先分析重复的常见原因
- 多RawContact对应同一个联系人:Android的联系人系统里,一个用户可见的联系人可能由多个
RawContact组成(比如联系人被合并过,或者在本地账户和Google账户下都有记录),直接查询RawContact就会返回多条重复数据。 - 未做去重处理:你的代码目前是直接把查询到的
RawContact加入列表,没有针对手机号做唯一性校验。
方案一:基于手机号直接去重(简单直接)
在添加联系人到列表前,先检查这个手机号是否已经存在,用HashSet来帮我们自动维护唯一性,同时可以统一手机号格式,避免因格式差异(比如带括号/空格和纯数字)导致的“伪重复”。
修改后的代码示例:
public static List<RawContact> getAllContacts(Context context, Account account) { Log.d(TAG, "*** Looking for local contacts with mobile number!!"); String phoneNumber = null; int numberOfContacts = 0; List<RawContact> newContacts = new ArrayList<>(); // 存储已处理过的手机号,避免重复 Set<String> existingPhoneNumbers = new HashSet<>(); // 你的RawContact查询逻辑(这里保留你原有的查询框架) String[] projection = {RawContacts._ID, RawContacts.DISPLAY_NAME_PRIMARY}; Cursor cursor = context.getContentResolver().query( RawContacts.CONTENT_URI, projection, RawContacts.ACCOUNT_TYPE + " = ?", new String[]{account.type}, null ); if (cursor != null) { while (cursor.moveToNext()) { // 获取当前RawContact对应的手机号(替换成你实际的手机号获取逻辑) phoneNumber = getPhoneNumberByRawContactId(context, cursor.getLong(cursor.getColumnIndex(RawContacts._ID))); if (phoneNumber != null && !phoneNumber.isEmpty()) { // 统一手机号格式:去掉所有非数字字符 String normalizedPhone = phoneNumber.replaceAll("[^0-9]", ""); // 检查手机号是否已存在,不存在再添加 if (!existingPhoneNumbers.contains(normalizedPhone)) { existingPhoneNumbers.add(normalizedPhone); // 初始化并添加RawContact到列表 RawContact contact = new RawContact(); // 设置联系人属性(比如姓名、ID等) contact.setId(cursor.getLong(cursor.getColumnIndex(RawContacts._ID))); contact.setName(cursor.getString(cursor.getColumnIndex(RawContacts.DISPLAY_NAME_PRIMARY))); contact.setPhone(normalizedPhone); newContacts.add(contact); numberOfContacts++; } } } cursor.close(); } Log.d(TAG, "Found " + numberOfContacts + " unique contacts with mobile numbers"); return newContacts; } // 辅助方法:根据RawContact ID获取手机号 private static String getPhoneNumberByRawContactId(Context context, long rawContactId) { String[] phoneProjection = {Phone.NUMBER}; Cursor phoneCursor = context.getContentResolver().query( Phone.CONTENT_URI, phoneProjection, Phone.RAW_CONTACT_ID + " = ?", new String[]{String.valueOf(rawContactId)}, null ); String number = null; if (phoneCursor != null && phoneCursor.moveToFirst()) { number = phoneCursor.getString(phoneCursor.getColumnIndex(Phone.NUMBER)); phoneCursor.close(); } return number; }
方案二:查询合并后的联系人(从根源避免重复)
如果你的需求是获取用户界面上看到的“合并后”联系人,而不是底层的RawContact,可以直接查询ContactsContract.Contacts表——这里的每个条目都是用户看到的唯一联系人,自然不会出现重复。
示例代码:
public static List<Contact> getAllUniqueVisibleContacts(Context context) { Log.d(TAG, "*** Looking for unique visible contacts with mobile number!!"); List<Contact> contacts = new ArrayList<>(); Set<String> existingPhones = new HashSet<>(); // 查询带手机号的合并后联系人 String[] contactProjection = { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY }; String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = 1"; Cursor contactCursor = context.getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, contactProjection, selection, null, null ); if (contactCursor != null) { while (contactCursor.moveToNext()) { long contactId = contactCursor.getLong(contactCursor.getColumnIndex(ContactsContract.Contacts._ID)); // 获取该联系人的所有手机号 Cursor phoneCursor = context.getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER}, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{String.valueOf(contactId)}, null ); if (phoneCursor != null) { while (phoneCursor.moveToNext()) { String phone = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); String normalizedPhone = phone.replaceAll("[^0-9]", ""); if (!existingPhones.contains(normalizedPhone)) { existingPhones.add(normalizedPhone); Contact contact = new Contact(); contact.setId(contactId); contact.setName(contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY))); contact.setPhone(normalizedPhone); contacts.add(contact); } } phoneCursor.close(); } } contactCursor.close(); } return contacts; }
小建议
- 如果需要针对特定账户处理联系人,方案一更适合;如果只是要展示用户看到的联系人列表,方案二更简洁。
- 测试时可以检查重复条目是否来自不同账户(比如本地账户和Google账户),这样能更精准定位问题根源。
内容的提问来源于stack exchange,提问作者Jeeva
相关产品推荐
相关产品推荐

