已实现Android全量联系人获取,咨询按类型分类的Cursor属性
获取Android联系人的存储类型(Google/SIM卡等)
你之前实现全量联系人获取的思路没问题,但要区分Google、SIM卡这类存储类型,可不能用ContactsContract.Contacts.GET_TYPE——这个字段是用来区分联系人分组类型的,和存储源完全不相关。正确的做法是从RawContacts表里读取账号相关字段,因为每个联系人的原始记录(RawContact)才对应着具体的存储来源(比如Google账号、SIM卡、本地存储等)。
关键字段说明
ContactsContract.RawContacts.ACCOUNT_TYPE:核心判断字段,返回账号的类型标识,不同存储源的标识有规律:- Google联系人:固定为
com.google - SIM卡联系人:常见值是
com.android.phone或com.android.contacts.sim(不同厂商可能略有差异) - 本地联系人:通常是
com.android.localphone
- Google联系人:固定为
ContactsContract.RawContacts.ACCOUNT_NAME:辅助验证字段,返回账号名称,比如SIM卡可能显示为SIM 1、中国移动等,能帮你进一步确认类型。
代码示例(按存储类型分类联系人)
要注意一个联系人可能同时存在于多个存储源(比如既在Google同步,又存在于SIM卡),所以得先拿到联系人ID,再查询对应的RawContacts记录来判断类型:
// 先处理权限(Android 6.0+必须动态申请READ_CONTACTS) if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 100); return; } // 初始化分类列表 Map<String, List<String>> contactTypeMap = new HashMap<>(); contactTypeMap.put("Google联系人", new ArrayList<>()); contactTypeMap.put("SIM卡联系人", new ArrayList<>()); contactTypeMap.put("本地联系人", new ArrayList<>()); contactTypeMap.put("其他类型", new ArrayList<>()); // 第一步:查询所有联系人的基础信息 Cursor contactCursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME}, null, null, null ); if (contactCursor != null && contactCursor.moveToFirst()) { do { String contactId = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts._ID)); String displayName = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); // 第二步:根据联系人ID查询对应的RawContacts,获取存储类型 Cursor rawContactCursor = getContentResolver().query( ContactsContract.RawContacts.CONTENT_URI, new String[]{ContactsContract.RawContacts.ACCOUNT_TYPE}, ContactsContract.RawContacts.CONTACT_ID + " = ?", new String[]{contactId}, null ); if (rawContactCursor != null && rawContactCursor.moveToFirst()) { do { String accountType = rawContactCursor.getString(rawContactCursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE)); String targetCategory = "其他类型"; // 根据账号类型匹配分类 if ("com.google".equals(accountType)) { targetCategory = "Google联系人"; } else if ("com.android.phone".equals(accountType) || "com.android.contacts.sim".equals(accountType)) { targetCategory = "SIM卡联系人"; } else if ("com.android.localphone".equals(accountType)) { targetCategory = "本地联系人"; } // 避免同一联系人重复添加到同一分类 if (!contactTypeMap.get(targetCategory).contains(displayName)) { contactTypeMap.get(targetCategory).add(displayName); } } while (rawContactCursor.moveToNext()); rawContactCursor.close(); } } while (contactCursor.moveToNext()); contactCursor.close(); } // 打印分类结果(也可以直接用分类列表做UI展示) for (Map.Entry<String, List<String>> entry : contactTypeMap.entrySet()) { Log.d("ContactGroup", entry.getKey() + ": " + entry.getValue().toString()); }
注意事项
- 权限必须到位:一定要申请
READ_CONTACTS权限,Android 6.0及以上版本记得动态申请,不然会直接崩溃。 - 适配厂商差异:部分国产手机的SIM卡或本地联系人
ACCOUNT_TYPE可能有自定义值,建议测试时先打印实际返回的accountType,再补充判断逻辑。 - 多存储源处理:同一个联系人可能属于多个分类,代码里做了去重,你可以根据需求调整是否允许重复添加。
内容的提问来源于stack exchange,提问作者Alex Tomei
相关产品推荐
相关产品推荐

