关于ContactsContract.Data.IS_READ_ONLY返回-1的技术问询
解决
IS_READ_ONLY标记返回-1的问题 先给你理清楚问题根源,再提供可行的解决方案:
首先明确官方对IS_READ_ONLY的定义:
- 常量名:
is_read_only - 类型:INTEGER
- 默认值:
0(表示该联系人条目可被修改/删除) - 当值为
1时:只有对应的同步适配器能修改或删除该行,其他应用无权限,逻辑与CALLER_IS_SYNCADAPTER标记关联
为什么所有联系人都返回-1?
你直接查询的是聚合后的Contacts表,但这个表的IS_READ_ONLY字段无法准确反映第三方同步联系人的只读状态。像WhatsApp、PayTM、Duo这类应用的联系人,都是通过各自的同步适配器创建的原始联系人(RawContacts),它们的只读属性存储在RawContacts表中,聚合后的Contacts条目并没有正确继承这个值,所以会返回-1(无明确设置的默认值)。
正确解决方案:查询RawContacts表
你需要直接查询RawContacts表,结合账户类型来识别第三方应用的只读联系人,示例代码如下:
// 指定要查询的字段,包含只读标记和账户信息 String[] projection = { ContactsContract.RawContacts._ID, ContactsContract.RawContacts.ACCOUNT_TYPE, ContactsContract.RawContacts.IS_READ_ONLY, ContactsContract.RawContacts.CONTACT_ID // 用于关联聚合联系人 }; Cursor rawContactsCursor = getContentResolver().query( ContactsContract.RawContacts.CONTENT_URI, projection, null, null, null ); if (rawContactsCursor != null && rawContactsCursor.moveToFirst()) { int readOnlyColIndex = rawContactsCursor.getColumnIndex(ContactsContract.RawContacts.IS_READ_ONLY); int accountTypeColIndex = rawContactsCursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE); int contactIdColIndex = rawContactsCursor.getColumnIndex(ContactsContract.RawContacts.CONTACT_ID); do { int isReadOnly = rawContactsCursor.getInt(readOnlyColIndex); String accountType = rawContactsCursor.getString(accountTypeColIndex); long contactId = rawContactsCursor.getLong(contactIdColIndex); // 识别第三方应用的只读联系人,这里以WhatsApp为例 if (isReadOnly == 1 && "com.whatsapp".equals(accountType)) { // 这是WhatsApp同步的只读联系人,contactId对应聚合后的联系人ID // 在这里处理你的业务逻辑 } } while (rawContactsCursor.moveToNext()); rawContactsCursor.close(); }
额外提示
- 不同应用的
ACCOUNT_TYPE是固定的,比如Google Duo的是com.google.android.apps.tachyon,PayTM的你可以通过打印日志获取具体值 - 务必确保你的应用已经获取了
READ_CONTACTS权限,Android 6.0及以上需要动态申请 - 部分第三方应用可能不会将联系人标记为只读,建议实际测试验证它们的
IS_READ_ONLY取值
内容的提问来源于stack exchange,提问作者Gvtha
相关产品推荐
相关产品推荐

