1

我正在创建一个联系人应用程序,它将具有联系人应用程序的所有基本功能(当然还有一些额外的功能)。在实现基本功能时,我被困在一个地方:

我正在进行一项活动,用户可以在其中更改联系人的城市名称。如果用户已经拥有一个城市,我可以使用以下代码对其进行更新:

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);

但是,上面的代码不适用于除了电话号码之外没有任何详细信息的联系人。浏览了很多之后,我找到了以下方法:

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);

在上述情况下,我得到的fromrawContactId等于正常的contactId。我为不同的帐户获得了不同的 rawContactId - Google、WhatsApp、Skype 等。我尝试使用所有 rawContactIds 进行更新,但仍然没有更新。任何人都可以帮我解决它吗?ContactsContract.RawContacts.CONTENT_URIContactsContract.Data.CONTACT_ID

4

1 回答 1

2

当您应用上述代码时,您没有指定究竟是什么不起作用,但我可以在其中看到一些问题。

首先你需要清楚地了解联系人数据是如何存储在数据库中的:

  1. Contacts- 每个条目代表一个联系人,并将一个或多个组合在一起RawContacts
  2. RawContacts- 每个条目代表一些SyncAdapter(例如 Whatsapp、Google、Facebook、Viber)同步的联系人数据,这将多个数据条目分组
  3. Data- 关于联系人、电子邮件、电话等的实际数据。每一行都是属于单个数据的单个数据RawContact

问题 1

因此,如果您尝试更新现有的邮政地址,则应注意不要使用contactId 作为您的密钥,因为单个联系人(由contactId 引用)可能在多个原始联系人中具有多个邮政地址,每个原始联系人都有多个邮政地址数据行。然后,您的newUpdate呼叫可能会更新所有地址中的城市。

因此,如果您的联系人“David”有地址:

  • 123 车道,纽约,美国
  • 456 drive, 密苏里州, 美国
  • 789胡同,巴黎,法国

并且您的用户现在正在尝试将“巴黎”更新为“里昂”,您的代码可能会将所有 3 个地址更新为里昂。

然后,您的密钥必须是您尝试更新Data._ID的特定行的当前行。Data

问题 2

如果您尝试将新数据行插入现有 raw-contact,例如全新的邮政地址,则需要指定您尝试插入的特定 RawContact ID,而不是使用withValueBackReference- 那是仅当您现在创建一个全新的 RawContact 并且不知道它将获得什么 RawContact ID 时才有用,因此您正在对新 RawContact 将从以前获得的 ID 进行反向引用调用 RawContact 行的 newInsert。

此外,在这种情况下,仅 CITY 值是不够的,因为您将获得仅由 CITY 组成的整个邮政地址,如下所示:

  • 123 车道,纽约,美国
  • 456 drive, 密苏里州, 美国
  • 789胡同,巴黎,法国
  • 里昂

您在这里要做的是收集所有邮政地址值,并将它们全部添加到一个新的数据行中,如下所示:

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值插入现有的邮政地址行,则需要对特定的数据 ID 进行更新,而不是插入,如下所示:

String selection = Data._ID + " = ?";
ops.add(
 ContentProviderOperation.newUpdate(Data.CONTENT_URI)
   .withSelection(selection, new String[]{ dataId })
   .withValue(StructuredPostal.CITY, "Los Angeles")
   .build()
);
于 2020-03-12T09:56:14.287 回答