如何使用 ContentProviderOperation 将城市字段添加到 Android 中的联系人
How to add city field to a contact in Android using ContentProviderOperation
我正在创建一个联系人应用程序,它将具有联系人应用程序的所有基本功能(当然还有一些额外的功能)。在实现基本功能时,我卡在了一个地方:
我有一个 activity,用户可以在其中更改联系人的城市名称。如果用户已经有一个城市,我可以使用以下代码更新它:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String contactId = id; // got it from ContactsContract.Contacts._ID
String mimeType = ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE;
String selection = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredPostal.TYPE + " = ?";
String[] values = new String[]{contactId, mimeType, String.valueOf(ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME)};
ops.add(
android.content.ContentProviderOperation.newUpdate(
android.provider.ContactsContract.Data.CONTENT_URI)
.withSelection(selection, values)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, "California")
.build()
);
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
但是,上面的代码不适用于除了 phone 号码之外没有任何详细信息的联系人。浏览了很多之后,我找到了以下方法:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String rawContactId = id;
String mimeType = ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE;
String[] values = new String[]{contactId, mimeType, String.valueOf(ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME)};
ops.add(
android.content.ContentProviderOperation.newInsert(
android.provider.ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
.withValue(ContactsContract.Data.MIMETYPE, mimeType)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, "California")
.build()
);
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
在上述情况下,我从 ContactsContract.RawContacts.CONTENT_URI
获得 rawContactId
,其中 ContactsContract.Data.CONTACT_ID
等于正常的 contactId。我为不同的帐户获得了不同的 rawContactId - Google、WhatsApp、Skype 等。我尝试使用所有 rawContactId 进行更新,但它仍然没有得到更新。谁能帮我解决一下?
当你应用上面的代码时,你没有具体说明是什么不起作用,但我可以看到其中的一些问题。
首先你需要清楚的了解联系人数据是如何存储在数据库中的:
Contacts
- 每个条目代表一个联系人,并将一个或多个 RawContacts
组合在一起
RawContacts
- 每个条目代表有关联系人的数据,这些数据由某些 SyncAdapter
(例如 Whatsapp、Google、Facebook、Viber)同步,这将多个数据条目分组
Data
- 有关联系人、电子邮件、电话等的实际数据。每行是属于单个 RawContact
的单个数据
问题 1
因此,如果您尝试 更新 现有的邮政地址,您应该注意不要使用 contactId 作为您的密钥,因为单个联系人(由 contactId 引用) 可能在多个原始联系人中有多个邮政地址,每个联系人都有多个邮政地址数据行。
然后,您的 newUpdate
调用可能会更新所有地址中的城市。
因此,如果您的联系人 "David" 的地址为:
- 123 巷,纽约,美国
- 456 车道,美国密苏里州
- 法国巴黎789巷
并且您的用户现在正在尝试将 "Paris" 更新为 "Lyon",您的代码可能会将所有 3 个地址更新为里昂。
您的密钥必须是您尝试更新的特定 Data
行的当前 Data._ID
。
问题 2
如果您尝试将新数据行插入现有原始联系人,例如一个全新的邮政-地址,您需要指定您要插入的特定 RawContact ID,而不是使用 withValueBackReference
- 这仅在您现在创建一个全新的 RawContact 并且不知道会发生什么时有用是它将获得的 RawContact ID,因此您正在对新 RawContact 将从先前调用 RawContact 行的 newInsert 获得的 ID 进行反向引用。
此外,在这种情况下,仅 CITY 值是不够的,因为您将获得仅由 CITY 组成的完整邮政地址,如下所示:
- 123 巷,纽约,美国
- 456 车道,美国密苏里州
- 法国巴黎789巷
- 里昂
您在这里要做的是收集所有邮政地址值,并将它们全部添加到一个新的 Data 行中,如下所示:
ops.add(
ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValue(Data.RAW_CONTACT_ID, rawContactId)
.withValue(Data.MIMETYPE, mimeType)
.withValue(StructuredPostal.STREET, "123 Lane")
.withValue(StructuredPostal.CITY, "Los Angles")
.withValue(StructuredPostal.REGION, "California")
.withValue(StructuredPostal.COUNTRY, "United States")
.build()
);
问题 3
如果您只想将 CITY 值插入 existing 邮政地址行,您需要执行以下操作对特定数据 ID 的更新,而不是插入,如下所示:
String selection = Data._ID + " = ?";
ops.add(
ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withSelection(selection, new String[]{ dataId })
.withValue(StructuredPostal.CITY, "Los Angeles")
.build()
);
我正在创建一个联系人应用程序,它将具有联系人应用程序的所有基本功能(当然还有一些额外的功能)。在实现基本功能时,我卡在了一个地方:
我有一个 activity,用户可以在其中更改联系人的城市名称。如果用户已经有一个城市,我可以使用以下代码更新它:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String contactId = id; // got it from ContactsContract.Contacts._ID
String mimeType = ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE;
String selection = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredPostal.TYPE + " = ?";
String[] values = new String[]{contactId, mimeType, String.valueOf(ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME)};
ops.add(
android.content.ContentProviderOperation.newUpdate(
android.provider.ContactsContract.Data.CONTENT_URI)
.withSelection(selection, values)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, "California")
.build()
);
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
但是,上面的代码不适用于除了 phone 号码之外没有任何详细信息的联系人。浏览了很多之后,我找到了以下方法:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String rawContactId = id;
String mimeType = ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE;
String[] values = new String[]{contactId, mimeType, String.valueOf(ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME)};
ops.add(
android.content.ContentProviderOperation.newInsert(
android.provider.ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
.withValue(ContactsContract.Data.MIMETYPE, mimeType)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, "California")
.build()
);
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
在上述情况下,我从 ContactsContract.RawContacts.CONTENT_URI
获得 rawContactId
,其中 ContactsContract.Data.CONTACT_ID
等于正常的 contactId。我为不同的帐户获得了不同的 rawContactId - Google、WhatsApp、Skype 等。我尝试使用所有 rawContactId 进行更新,但它仍然没有得到更新。谁能帮我解决一下?
当你应用上面的代码时,你没有具体说明是什么不起作用,但我可以看到其中的一些问题。
首先你需要清楚的了解联系人数据是如何存储在数据库中的:
Contacts
- 每个条目代表一个联系人,并将一个或多个RawContacts
组合在一起
RawContacts
- 每个条目代表有关联系人的数据,这些数据由某些SyncAdapter
(例如 Whatsapp、Google、Facebook、Viber)同步,这将多个数据条目分组Data
- 有关联系人、电子邮件、电话等的实际数据。每行是属于单个RawContact
的单个数据
问题 1
因此,如果您尝试 更新 现有的邮政地址,您应该注意不要使用 contactId 作为您的密钥,因为单个联系人(由 contactId 引用) 可能在多个原始联系人中有多个邮政地址,每个联系人都有多个邮政地址数据行。
然后,您的 newUpdate
调用可能会更新所有地址中的城市。
因此,如果您的联系人 "David" 的地址为:
- 123 巷,纽约,美国
- 456 车道,美国密苏里州
- 法国巴黎789巷
并且您的用户现在正在尝试将 "Paris" 更新为 "Lyon",您的代码可能会将所有 3 个地址更新为里昂。
您的密钥必须是您尝试更新的特定 Data
行的当前 Data._ID
。
问题 2
如果您尝试将新数据行插入现有原始联系人,例如一个全新的邮政-地址,您需要指定您要插入的特定 RawContact ID,而不是使用 withValueBackReference
- 这仅在您现在创建一个全新的 RawContact 并且不知道会发生什么时有用是它将获得的 RawContact ID,因此您正在对新 RawContact 将从先前调用 RawContact 行的 newInsert 获得的 ID 进行反向引用。
此外,在这种情况下,仅 CITY 值是不够的,因为您将获得仅由 CITY 组成的完整邮政地址,如下所示:
- 123 巷,纽约,美国
- 456 车道,美国密苏里州
- 法国巴黎789巷
- 里昂
您在这里要做的是收集所有邮政地址值,并将它们全部添加到一个新的 Data 行中,如下所示:
ops.add(
ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValue(Data.RAW_CONTACT_ID, rawContactId)
.withValue(Data.MIMETYPE, mimeType)
.withValue(StructuredPostal.STREET, "123 Lane")
.withValue(StructuredPostal.CITY, "Los Angles")
.withValue(StructuredPostal.REGION, "California")
.withValue(StructuredPostal.COUNTRY, "United States")
.build()
);
问题 3
如果您只想将 CITY 值插入 existing 邮政地址行,您需要执行以下操作对特定数据 ID 的更新,而不是插入,如下所示:
String selection = Data._ID + " = ?";
ops.add(
ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withSelection(selection, new String[]{ dataId })
.withValue(StructuredPostal.CITY, "Los Angeles")
.build()
);