代码之家  ›  专栏  ›  技术社区  ›  Daniel James

如何使用ContentProviderOperation将city字段添加到Android联系人中

  •  0
  • Daniel James  · 技术社区  · 5 年前

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

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

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

    在上述情况下,我得到 rawContactId ContactsContract.RawContacts.CONTENT_URI 具有 ContactsContract.Data.CONTACT_ID 等于正常的contactId。我为不同的账户获得了不同的rawContactId——谷歌、WhatsApp、Skype等等。我尝试用所有的rawContactId进行更新,但仍然没有得到更新。谁能帮我修一下吗?

    0 回复  |  直到 5 年前
        1
  •  2
  •   marmor    5 年前

    在应用上述代码时,您没有具体说明什么不起作用,但我可以看到其中的一些问题。

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

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

    问题1

    所以如果你想 使现代化 对于现有的邮政地址,您应该小心不要使用contactId作为密钥,因为单个联系人(由contactId引用)可能在多个原始联系人中有多个邮政地址,每个联系人都有多个邮政地址数据行。 你的 newUpdate 然后,电话可能会更新城市的所有地址。

    所以如果你有一个有地址的联系人“David”:

    • 美国纽约莱恩123号
    • 美国密苏里州大道456号
    • 法国巴黎巷789号

    而你的用户现在正试图将“Paris”更新为“Lyon”,你的代码可能会将所有3个地址更新为Lyon。

    你的钥匙必须是当前的 Data._ID 具体的 数据 您要更新的行。

    问题2

    如果你想插入 新数据行 现有原始联系人 ,例如,如果是一个全新的邮政地址,则需要指定要插入但不使用的特定联系人ID withValueBackReference -只有当您现在创建一个全新的RawContact,并且不知道它将获得什么样的RawContact ID时,这才有用,因此您正在对新的RawContact将从之前对RawContact行的newInsert调用中获得的ID进行反向引用。

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

    • 美国纽约莱恩123号
    • 美国密苏里州大道456号
    • 法国巴黎巷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

    如果你只是想插入 城市 价值观 现有的 “邮政地址”行中,您需要对特定的数据ID进行更新,而不是插入,如下所示:

    String selection = Data._ID + " = ?";
    ops.add(
     ContentProviderOperation.newUpdate(Data.CONTENT_URI)
       .withSelection(selection, new String[]{ dataId })
       .withValue(StructuredPostal.CITY, "Los Angeles")
       .build()
    );