Как добавить поле города к контакту в Android с помощью ContentProviderOperation - PullRequest
1 голос
/ 11 марта 2020

Я создаю приложение контактов, которое будет иметь все основные c функции приложения Контакты (и, конечно, некоторые дополнительные функции). При реализации основных функций c я застрял в одном месте:

У меня есть действие, в котором пользователь может изменить название города для контакта. Если у пользователя уже есть город, я могу обновить его, используя следующий код:

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 для разных учетных записей - Google, WhatsApp, Skype и др. c. Я попытался обновить все rawContactIds, но все равно он не обновлялся. Кто-нибудь может помочь мне как это исправить?

1 Ответ

2 голосов
/ 12 марта 2020

Вы не указали, что именно не работает, когда применяете приведенный выше код, но я вижу в нем несколько проблем.

Прежде всего необходимо четко понимать, как хранятся контактные данные. в базе данных:

  1. Contacts - каждая запись представляет один контакт и группирует один или несколько RawContacts
  2. RawContacts - каждая запись представляет данные о контакте, которые был синхронизирован с некоторыми SyncAdapter (например, Whatsapp, Google, Facebook, Viber), это группирует несколько записей данных
  3. Data - фактические данные о контакте, электронные письма, телефоны и т. д. c. каждая строка представляет собой отдельный фрагмент данных, принадлежащий одному RawContact

ВЫПУСК 1

Так что, если вы пытаетесь обновить существующий почтовый адрес, вы должны быть осторожны, чтобы не использовать contactId в качестве ключа, потому что один контакт (на который ссылается contactId) может иметь несколько почтовых адресов в нескольких raw-контактах, каждый с несколькими строками данных почтового адреса , Ваш newUpdate вызов может затем обновить город во ВСЕХ адресах.

Так что если у вас есть контакт "Дэвид", который имеет адреса:

  • 123 переулок, Нью-Йорк, США
  • 456 диск, Миссури, США
  • 789 аллея, Париж, Франция

и ваш пользователь сейчас пытается обновить "Париж" до "Лиона", Ваш код может обновить ВСЕ 3 адреса до Lyon.

Ваш ключ должен быть текущей Data._ID указанной строки c Data, которую вы пытаетесь обновить.

ВЫПУСК 2

Если вы пытаетесь вставить новую строку данных в существующий необработанный контакт , например, совершенно новый почтовый адрес адрес, вам нужно указать указанный c RawContact ID, в который вы пытаетесь вставить, а не использовать withValueBackReference - это полезно только тогда, когда вы создаете целый новый RawContact, и не знаете, что будет идентификатором RawContact, который он получит, поэтому вы делаете обратную ссылку на идентификатор, который ваш новый RawContact получит из предыдущего ous вызов newInsert строки RawContact.

Кроме того, в этом случае просто недостаточно значения 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()
);

ISSUE 3

Если вы пытаетесь вставить только значение CITY в существующую строку почтового адреса, вам необходимо выполнить обновить, а не вставить, в специфицированный c ID данных, что-то вроде этого:

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