lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

Поставщик контактов

Поставщик контактов представляет собой эффективный и гибкий компонент Android, который управляет центральным репозиторием устройства, в котором хранятся пользовательские данные. Поставщик контактов — это источник данных, которые отображаются в приложении «Контакты» на вашем устройстве. Вы также можете получить доступ к этим данным в своем собственном приложении и организовать обмен такими данными между устройством и службами в Интернете. Поставщик взаимодействует с широким набором источников данных и пытается организовать управление как можно большим набором данных о каждом человеке, поэтому организация поставщика довольно сложная. По этой причине API поставщика содержит широкий набор классов-контрактов и интерфейсов, отвечающих как за получение данных, так и за их изменение.

В этом руководстве рассматриваются следующие вопросы:

  • основная структура поставщика;
  • порядок получения данных от поставщика;
  • порядок изменения данных в поставщике;
  • порядок записи адаптера синхронизации для синхронизации данных, полученных с вашего сервера, с данными в поставщике контактов.

При изучении данного материала подразумевается, что вы уже знакомы с основами поставщиков контента Android. Дополнительные сведения о поставщиках контента Android представлены в руководстве Основные сведения о поставщике контента. Пример адаптера синхронизации служит примером использования такого приложения для обмена данными между поставщиком контактов и приложением, размещенным в веб-службах Google.

Структура поставщика контактов

Поставщик контактов представляет собой поставщик контента Android. Он содержит в себе три типа данных о пользователе, каждый из которых указан в отдельной таблице, предоставляемой поставщиком, как показано на рисунке 1.

Рисунок 1. Структура таблицы поставщика контактов.

В качестве имен этих трех таблиц обычно используются названия соответствующих классов-контрактов. Эти классы определяют константы для URI контента, названий столбцов и значений в столбцах этих таблиц.

Таблица ContactsContract.Contacts
Строки в этой таблице содержат данные о разных пользователях, полученные путем агрегации строк необработанных контактов.
Таблица ContactsContract.RawContacts
Строки в этой таблице содержат сводные данные о пользователе, относящиеся к пользовательскому аккаунту и его типу.
Таблица ContactsContract.Data
Строки в этой таблице содержат сведения о необработанных контактах, такие как адреса эл. почты или номера телефонов.

Другие таблицы, представленные классами-контрактами в ContactsContract, представляют собой вспомогательные таблицы, которые поставщик контактов использует для управления своими операциями или поддержки определенных функций, имеющихся в приложении устройства «Контакты» или приложениях для телефонной связи.

Необработанные контакты

Необработанный контакт представляет собой данные о пользователе, поступающие из одного аккаунта определенного типа. Поскольку в качестве источника данных о пользователе в поставщике контактов может выступать сразу несколько онлайн-служб, для одного и того же пользователя в поставщике контактов может существовать несколько необработанных контактов. Это также позволяет пользователю объединять пользовательские данные из нескольких аккаунтов одного и того же типа.

Большая часть данных необработанного контакта не хранится в таблице ContactsContract.RawContacts. Вместо этого они хранятся в одной или нескольких строках в таблице ContactsContract.Data. В каждой строке данных имеется столбец Data.RAW_CONTACT_ID, в котором содержится значение android.provider.BaseColumns#_ID RawContacts._ID его родительской строкиContactsContract.RawContacts.

Важные столбцы необработанных контактов

В таблице 1 указаны столбцы таблицы ContactsContract.RawContacts, которые имеют большое значение. Обязательно ознакомьтесь с примечаниями, приведенными после этой таблицы.

Таблица 1. Важные столбцы необработанных контактов.

Название столбца Использование Примечания
ACCOUNT_NAME Имя аккаунта для типа аккаунта, который выступает в роли источника данных для необработанного контакта. Например, имя аккаунта Google является одним из эл. адресов почты Gmail владельца устройства. Дополнительные сведения см. в следующей записи ACCOUNT_TYPE. Формат этого имени зависит от типа аккаунта. Это не обязательно адрес эл. почты.
ACCOUNT_TYPE Тип аккаунта, который выступает в роли источника данных для необработанного контакта. Например, тип аккаунта Google — com.google. Всегда указывайте тип аккаунта и идентификатор домена, которым вы владеете или управляете. Это позволит гарантировать уникальность типа вашего аккаунта. У типа аккаунта, выступающего в роли источника данных контактов, обычно имеется связанный с ним адаптер синхронизации, который синхронизирует данные с поставщиком контактов.
DELETED Флаг deleted для необработанного контакта. Этот флаг позволяет поставщику контактов хранить строку внутри себя до тех пор, пока адаптеры синхронизации не смогут удалить эту строку с серверов, а затем удалить ее из репозитория.

Примечания

Ниже представлены важные примечания к таблице ContactsContract.RawContacts.

  • Имя необработанного контакта не хранится в его строке в таблице ContactsContract.RawContacts. Вместо этого оно хранится в таблице ContactsContract.Data в строке ContactsContract.CommonDataKinds.StructuredName. У необработанного контакта имеется в таблице ContactsContract.Data только одна строка такого типа.
  • Внимание! Чтобы использовать в строке необработанного контакта данные собственного аккаунта, строку , сначала необходимо зарегистрировать его в классе AccountManager. Для этого предложите пользователям добавить тип аккаунта и его имя в список аккаунтов. Если не сделать этого, поставщик контактов автоматически удалит вашу строку необработанного контакта.

    Например, если необходимо, чтобы в вашем приложении хранились данные контактов для веб-службы в домене com.example.dataservice, и аккаунт пользователя службы выглядит следующим образом:becky.sharp@dataservice.example.com, то пользователю сначала необходимо добавить «тип» аккаунта (com.example.dataservice) и его «имя» (becky.smart@dataservice.example.com) прежде чем ваше приложение сможет добавлять строки необработанных контактов. Это требование можно указать в документации для пользователей, а также можно предложить пользователю добавить тип и имя своего аккаунта, либо реализовать оба этих варианта. Более подробно типы и имена аккаунтов рассматриваются в следующем разделе.

Источники данных необработанных контактов

Чтобы понять, что такое необработанный контакт, рассмотрим пример с пользователем Emily Dickinson, на устройстве которой имеется три следующих аккаунта:

  • emily.dickinson@gmail.com;
  • emilyd@gmail.com;
  • Аккаунт belle_of_amherst в Twitter

Она включила функцию Синхронизировать контакты для всех трех этих аккаунтов в настройках Аккаунты.

Предположим, что Emily Dickinson открывает браузер, входит в Gmail под именем emily.dickinson@gmail.com, затем открывает Контакты и добавляет новый контакт Thomas Higginson. Позже она снова входит в Gmail под именем emilyd@gmail.com и отправляет письмо пользователю Thomas Higginson, который автоматически добавляется в ее контакты. Также она подписана на новости от colonel_tom (аккаунт пользователя Thomas Higginson в Twitter) в Twitter.

В результате этих действий поставщик контактов создает три необработанных контакта:

  1. Необработанный контакт Thomas Higginson связан с аккаунтом emily.dickinson@gmail.com. Тип этого аккаунта — Google.
  2. Второй необработанный контакт Thomas Higginson связан с аккаунтом emilyd@gmail.com. Тип этого аккаунта — также Google. Второй необработанный контакт создается даже в том случае, если его имя полностью совпадает с именем предыдущего контакта, поскольку первый был добавлен для другого аккаунта.
  3. Третий необработанный контакт Thomas Higginson связан с аккаунтом belle_of_amherst. Тип этого аккаунта — Twitter.

Данные

Как уже указывалось ранее, данные необработанного контакта хранятся в строке ContactsContract.Data, которая связана со значением _ID необработанного контакта. Благодаря этому для одного необработанного контакта может существовать несколько экземпляров одного и того же типа данных (например, адресов эл. почты или номеров телефонов). Например, если у контакта Thomas Higginson для аккаунта emilyd@gmail.com (строка необработанного контакта Thomas Higginson, связанная с учетной записью Google emilyd@gmail.com) имеется адрес эл. почты thigg@gmail.com и служебный адрес эл. почты thomas.higginson@gmail.com, то поставщик контактов сохраняет две строки адреса эл. почты и связывает их с этим необработанным контактом.

Обратите внимание, что в этой таблице хранятся данные разных типов. Строки со сведениями об отображаемом имени, номере телефона, адресе эл. почты, почтовом адресе, фото и веб-сайте хранятся в таблице ContactsContract.Data. Для упрощения управления этими данными в таблице ContactsContract.Data предусмотрены столбцы с описательными именами, а также другие столбцы с универсальными именами. Содержимое в столбце с описательным именем имеет то же значение, независимо от типа данных в строке, тогда как содержимое столбца с универсальным именем может иметь разное значение в зависимости от типа данных.

Описательные имена столбцов

Вот некоторые примеры столбцов с описательными именами:

RAW_CONTACT_ID
Значение в столбце _ID необработанного контакта для этих данных.
MIMETYPE
Тип данных, хранящихся в этой строке, в виде настраиваемого типа MIME. Поставщик контактов использует типы MIME, заданные в подклассах класса ContactsContract.CommonDataKinds. Эти типы MIME являются открытыми, и их может использовать любое приложение или адаптер синхронизации, поддерживающие работу с поставщиком контактов.
IS_PRIMARY
Если этот тип данных для необработанного контакта встречается несколько раз, то столбец IS_PRIMARY помечает флагом строки данных, в которых содержатся основные данные для этого типа. Например, если пользователь нажал и удерживает номер телефона контакта и выбрал параметр Использовать по умолчанию, то в столбце ContactsContract.Data с этим номером телефона в соответствующем столбце IS_PRIMARY задается значение, отличное от нуля.

Универсальные имена столбцов

Существует 15 общедоступных столбцов с универсальными именами (DATA1DATA15) и четыре дополнительных столбца (SYNC1SYNC4), которые используются только адаптерами синхронизации. Константы столбцов с универсальными именами применяются всегда, независимо от типа данных, содержащихся в столбце.

Столбец DATA1 является индексируемым. Поставщик контактов всегда использует этот столбец для данных, которые, как он ожидает, будут наиболее часто являться целевыми в запросах. Например, в строке с адресами эл. почты в этом столбце указывается фактический адрес эл. почты.

Обычно столбец DATA15 зарезервирован для данных больших двоичных объектов (BLOB), таких как миниатюры фотографий.

Имена столбцов по типам строк

Для упрощения работы со столбцами определенного типа строк в поставщике контактов также предусмотрены константы для имен столбцов по типам строк, которые определены в подклассах класса ContactsContract.CommonDataKinds. Эти константы просто присваивают одному и тому же имени столбца различные константы, что позволяет вам получать доступ к данным в строке определенного типа.

Например, класс ContactsContract.CommonDataKinds.Email определяет константы имени столбца для строки ContactsContract.Data, в которой имеется тип MIME Email.CONTENT_ITEM_TYPE. В этом классе содержится константа ADDRESS для столбца адреса эл. почты. Фактическое значение ADDRESS — data1, которое совпадает с универсальным именем столбца.

Внимание! Не добавляйте свои настраиваемые данные в таблицу ContactsContract.Data с помощью строки, в которой имеется один из предварительно заданных поставщиком типов MIME. В противном случае вы можете потерять данные или вызвать неполадки в работе поставщика. Например, не следует добавлять строку с типом MIME Email.CONTENT_ITEM_TYPE, в которой в столбце DATA1 вместо адреса эл. почты содержится имя пользователя. Если вы укажете в строке собственный настраиваемый тип MIME, вы можете свободно указывать собственные имена столбцов по типам строк и использовать их так, как пожелаете.

На рисунке 2 показано, как столбцы с описательными именами и столбцы данных отображаются в строке ContactsContract.Data, а также как имена столбцов по типу строк «накладываются» на универсальные имена столбцов.

How type-specific column names map to generic column names

Рисунок 2. Имена столбцов по типам строк и универсальные имена столбцов.

Классы имен столбцов по типам строк

В таблице 2 перечислены наиболее часто используемые классы имен столбцов по типам строк.

Таблица 2. Классы имен столбцов по типам строк

Класс сопоставления Тип данных Примечания
ContactsContract.CommonDataKinds.StructuredName Данные об имени необработанного контакта, связанного с этой строкой данных. У необработанного контакта имеется только одна строка такого типа.
ContactsContract.CommonDataKinds.Photo Основная фотография необработанного контакта, связанного с этой строкой данных. У необработанного контакта имеется только одна строка такого типа.
ContactsContract.CommonDataKinds.Email Адрес эл. почты необработанного контакта, связанного с этой строкой данных. У необработанного контакта может быть несколько адресов эл. почты.
ContactsContract.CommonDataKinds.StructuredPostal Почтовый адрес необработанного контакта, связанного с этой строкой данных. У необработанного контакта может быть несколько почтовых адресов.
ContactsContract.CommonDataKinds.GroupMembership Идентификатор, с помощью которого необработанный контакт связан с одной из групп в поставщике контактов. Группы представляют собой необязательный компонент для типа аккаунта и имени аккаунта. Дополнительные сведения о группах представлены в разделе Группы контактов.

Контакты

Поставщик контактов объединяет строки с необработанными контактами для всех типов аккаунтов и имен аккаунтов для создания контакта. Это позволяет упростить отображение и изменение всех данных, собранных в отношении пользователя. Поставщик контактов управляет процессом создания строк контактов и агрегированием необработанных контактов, у которых имеется строка контакта. Ни приложениям, ни адаптерам синхронизации не разрешается добавлять контакты, а некоторые столбцы в строке контакта доступны только для чтения.

Примечание. Если попытаться добавить контакт в поставщик контактов с помощью метода insert(), будет выдано исключение UnsupportedOperationException. Если вы попытаетесь обновить столбец, доступный только для чтения, это действие будет проигнорировано.

При добавлении нового необработанного контакта, который не соответствует ни одному из существующих контактов, поставщик контактов создает новый контакт. Поставщик поступает аналогично в случае, если данные в строке существующего необработанного контакта изменяются таким образом, что они больше не соответствуют контакту, с которым они ранее были связаны. При создании приложением или адаптером синхронизации нового контакта, который соответствует существующему контакту, то новый контакт объединяется с существующим контактом.

Поставщик контактов связывает строку контакта с его строками необработанного контакта посредством столбца _ID строки контакта в таблице Contacts. Столбец CONTACT_ID в таблице необработанных контактов ContactsContract.RawContacts содержит значения _ID для строки контактов, связанной с каждой строкой необработанных контактов.

В таблице ContactsContract.Contacts также имеется столбец android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY, который выступает в роли «постоянной ссылки» на строку контакта. Поскольку поставщик контактов автоматически сохраняет контакты, в ответ на агрегирование или синхронизацию он может изменить значение android.provider.BaseColumns#_ID строки контакта. Даже если это произойдет, URI контента CONTENT_LOOKUP_URI, объединенный с android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY контакта, будет по-прежнему указывать на строку контакта, поэтому вы можете смело использовать android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY для сохранения ссылок на «избранные» контакты и др. Столбец имеет собственный формат, который не связан с форматом столбцаandroid.provider.BaseColumns#_ID.

На рисунке 3 показаны взаимосвязи этих трех основных таблиц друг с другом.

Contacts provider main tables

Рисунок 3. Взаимосвязи между таблицами контактов, необработанных контактов и сведений.

Данные, полученные от адаптеров синхронизации

Пользователь вводит данные контактов прямо на устройстве, однако данные также поступают в поставщик контактов из веб-служб посредством адаптеров синхронизации, что позволяет автоматизировать обмен данными между устройством и службами в Интернете. Адаптеры синхронизации выполняются в фоновом режиме под управлением системы, и для управления данными они вызывают методы ContentResolver.

В Android веб-служба, с которой работает адаптер синхронизации, определяется по типу аккаунта. Каждый адаптер синхронизации работает с одним типом аккаунта, однако он может поддерживать несколько имен аккаунтов такого типа. Вкратце типы и имена аккаунтов рассматриваются в разделе Источники данных необработанных контактов. Указанные ниже определения позволяют более точно охарактеризовать связь между типами и именами аккаунтов и адаптерами синхронизации и службами.

Тип аккаунта
Определяет службу, в которой пользователь хранит данные. В большинстве случаев для работы со службой пользователю необходимо пройти проверку подлинности. Например, Google Контакты представляет собой тип аккаунтов, обозначаемый кодом google.com. Это значение соответствует типу аккаунта, используемого AccountManager.
Имя аккаунта
Определяет конкретный аккаунт или имя для входа для типа аккаунта. Аккаунты «Контакты Google» — это то же, что и аккаунты Google, в качестве имени которых используется адрес эл. почты. В других службах может использоваться имя пользователя, состоящее из одного слова, или числовой идентификатор.

Типы аккаунтов не обязательно должны быть уникальными. Пользователь может создать несколько аккаунтов Google Контакты и загрузить данные из них в поставщик контактов; это может произойти в случае, если у пользователя имеется один набор персональных контактов для личного аккаунта, и другой набор — для служебного аккаунта. Имена аккаунтов обычно уникальные. Вместе они формируют определенный поток данных между поставщиком контактов и внешними службами.

Если необходимо передать данные из службы в поставщик контактов, необходимо создать собственный адаптер синхронизации. Дополнительные сведения об этом представлены в разделе Адаптеры синхронизации поставщика контактов.

На рисунке 4 показано, какую роль выполняет поставщик контактов в потоке передачи данных о пользователях. В области, отмеченной на рисунке как sync adapters, каждый адаптер промаркирован в соответствии с поддерживаемым им типом аккаунтов.

Flow of data about people

Рисунок 4. Поток передачи данных через поставщика контактов.

Требуемые разрешения

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

Доступ на чтение одной или нескольких таблиц
READ_CONTACTS, указанный в файле AndroidManifest.xml с элементом <uses-permission> в виде <uses-permission android:name="android.permission.READ_CONTACTS">.
Доступ на запись в одну или несколько таблиц
WRITE_CONTACTS, указанный в файле AndroidManifest.xml с элементом <uses-permission> в виде <uses-permission android:name="android.permission.WRITE_CONTACTS">.

Эти разрешения не распространяются на работу с данными профиля пользователя. Профиль пользователя и требуемые разрешения для работы с ним рассматриваются в разделе Профиль пользователя ниже.

Помните, что данные о контактах пользователя являются личными и конфиденциальными. Пользователи заботятся о своей конфиденциальности, поэтому не хотят, чтобы приложения собирали данные о них самих или их контактах. Если пользователю не до конца ясно, для чего требуется разрешение на доступ к данным контактов, они могут присвоить вашему приложению низкий рейтинг или вообще откажутся его устанавливать.

Профиль пользователя

В таблице ContactsContract.Contacts имеется всего одна строка, содержащая данные профиля для устройства пользователя. Эти данные описывают user устройства, а не один из контактов пользователя. Строка контактов профиля связана со строкой необработанных контактов в каждой из систем, в которой используется профиль. В каждой строке необработанного контакта профиля может содержаться несколько строк данных. Константы для доступа к профилю пользователя представлены в классе ContactsContract.Profile.

Для доступа к профилю пользователя требуются особые разрешения. Кроме разрешений READ_CONTACTS и WRITE_CONTACTS, которые требуются для чтения и записи, для доступа к профилю пользователя необходимы разрешения android.Manifest.permission#READ_PROFILE и android.Manifest.permission#WRITE_PROFILE на чтение и запись соответственно.

Всегда следует помнить, что профиль пользователя представляет собой конфиденциальную информацию. Разрешение android.Manifest.permission#READ_PROFILE предоставляет вам доступ к личной информации на устройстве пользователя. В описании своего приложения обязательно укажите, для чего вам требуется доступ к профилю пользователя.

Чтобы получить строку контакта с профилем пользователя, вызовите метод ContentResolver.query(). Задайте для URI контента значение CONTENT_URI и не указывайте никаких критериев выборки. Этот URI контента также можно использовать в качестве основного URI для получения необработанных контактов или данных профиля. Ниже представлен фрагмент кода для получения данных профиля.

// Sets the columns to retrieve for the user profile
mProjection = new String[]
    {
        Profile._ID,
        Profile.DISPLAY_NAME_PRIMARY,
        Profile.LOOKUP_KEY,
        Profile.PHOTO_THUMBNAIL_URI
    };

// Retrieves the profile from the Contacts Provider
mProfileCursor =
        getContentResolver().query(
                Profile.CONTENT_URI,
                mProjection ,
                null,
                null,
                null);

Примечание. Если при извлечении несколько строк контактов необходимо определить, какой из них является профилем пользователя, обратитесь к столбцу IS_USER_PROFILE этой строки. Если в этом столбце указано значение «1», то в это строке находится профиль пользователя.

Метаданные поставщика контактов

Поставщик контактов управляет данными, которые используются для отслеживания состояния данных контакта в репозитории. Эти метаданные о репозитории хранятся в различных местах, включая строки необработанных контактов, данные и строки таблицы контактов, таблицу ContactsContract.Settings и таблицу ContactsContract.SyncState. В таблице ниже указаны значения каждого из этих фрагментов метаданных.

Таблица 3. Метаданные в поставщике контактов

Таблица Столбец Значения Описание
ContactsContract.RawContacts DIRTY «0» — с момента последней синхронизации изменения не вносились. Служит для отметки необработанных контактов, которые были изменены на устройстве и которые необходимо снова синхронизировать с сервером. Значение устанавливается автоматически поставщиком контактов при обновлении строк приложениями Android.

Адаптеры синхронизации, которые вносят изменения в необработанные контакты или таблицы данных, должны всегда добавлять к используемому ими URI контента строку CALLER_IS_SYNCADAPTER. Это позволяет предотвратить пометку таких строк поставщиком как «грязных». В противном случае изменения, внесенные адаптером синхронизации, будут рассматриваться как локальные изменения, которые подлежат отправке на сервер, даже если источником таких изменений был сам сервер.

«1» — с момента последней синхронизации были внесены изменения, которые необходимо отразить и на сервере.
ContactsContract.RawContacts VERSION Номер версии этой строки. Поставщик контактов автоматически увеличивает это значение при каждом изменении в строке или в связанных с ним данных.
ContactsContract.Data DATA_VERSION Номер версии этой строки. Поставщик контактов автоматически увеличивает это значение при каждом изменении в строке данных.
ContactsContract.RawContacts SOURCE_ID Строковое значение, которое служит уникальным идентификатором данного необработанного контакта в аккаунте, в котором он был создан. Когда адаптер синхронизации создает новый необработанный контакт, в этом столбце следует указать уникальный идентификатор этого необработанного контакта на сервере. Когда же приложение Android создает новый необработанный контакт, то приложению следует оставить этот столбец пустым. Это служит сигналом для адаптера синхронизации, чтобы создать новый необработанный контакт на сервере и получить значение SOURCE_ID.

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

  • Уникальный: у каждого необработанного контакта для аккаунта должен быть свой собственный идентификатор источника. Если не применить это требование, у вас обязательно возникнут проблемы с приложением «Контакты». Обратите внимание, что два необработанных контакта одного и того же типа аккаунта могут иметь одинаковый идентификатор источника. Например, необработанный контакт Thomas Higginson для аккаунта emily.dickinson@gmail.com может иметь такой же идентификатор источника, что и контакт Thomas Higginson для аккаунта emilyd@gmail.com.
  • Стабильный: идентификаторы источников представляют собой неизменную часть данных онлайн-службы для необработанного контакта. Например, если пользователь выполняет повторную синхронизацию после очистки хранилища контактов в настройках приложения, идентификаторы источников восстановленных необработанных контактов должны быть такими же, как и прежде. Если не применить это требование, перестанут работать ярлыки.
ContactsContract.Groups GROUP_VISIBLE «0» — контакты, представленные в этой группе, не должны отображаться в интерфейсах пользователя приложений Android. Этот столбец предназначен для сведений о совместимости с серверами, позволяющими пользователям скрывать контакты в определенных группах.
«1» — контакты, представленные в этой группе, могут отображаться в интерфейсах пользователя приложений.
ContactsContract.Settings UNGROUPED_VISIBLE «0» — для этого аккаунта и аккаунтов этого типа контакты, не принадлежащие к группе, не отображаются в интерфейсах пользователя приложений Android. По умолчанию контакты скрыты, если ни один из их необработанных контактов не принадлежит группе (принадлежность необработанного контакта к группе указывается в одном или нескольких строках ContactsContract.CommonDataKinds.GroupMembership в таблице ContactsContract.Data). Установив этот флаг в строке таблицы ContactsContract.Settings для типа аккаунта и имени аккаунта, вы можете принудительно сделать видимыми контакты, не принадлежащие какой-либо группе. Один из вариантов использования этого флага — отображение контактов с серверов, на которых не используются группы.
«1» — для этого аккаунта и аккаунтов этого типа контакты, не принадлежащие к группе, отображаются в интерфейсах пользователя приложений Android.
ContactsContract.SyncState (все) Эта таблица используется для хранения метаданных для вашего адаптера синхронизации. С помощью этой таблицы вы можете на постоянной основе хранить на устройстве сведения о состоянии синхронизации и другие связанные с синхронизацией данные.

Доступ к поставщику контактов

В этом разделе рассматриваются инструкции по получению доступа к данным из поставщика контактов, в частности, следующие:

  • запросы объектов;
  • пакетное изменение;
  • получение и изменение данных с помощью намерений;
  • целостность данных.

Дополнительные сведения о внесении изменений с помощью адаптеров синхронизации представлены в разделе Адаптеры синхронизации поставщика контактов.

Запрос объектов

Таблицы поставщика контактов имеют иерархическую структуру, поэтому зачастую полезно извлекать строку и все связанные с ней ее дочерние строки. Например, для отображения всей информации о пользователе вы, возможно, захотите извлечь все строки ContactsContract.RawContacts для одной строки ContactsContract.Contacts или все строки ContactsContract.CommonDataKinds.Email для одной строки ContactsContract.RawContacts. Чтобы упростить этот процесс, в поставщике контактов имеются объекты, которые выступают в роли соединителей базы данных между таблицами.

Объект представляет собой подобие таблицы, состоящей из выбранных столбцов родительской таблицы и ее дочерней таблицы. При запросе объекта вы предоставляете проекцию и критерии поиска на основе доступных в объекте столбцов. В результате вы получаете объект Cursor, в котором содержится одна строка для каждой извлеченной строки дочерней таблицы. Например, если запросить объект ContactsContract.Contacts.Entity для имени контакта и все строки ContactsContract.CommonDataKinds.Email для всех необработанных контактов, соответствующих этому имени, вы получите объект Cursor, содержащий по одной строке для каждой строки ContactsContract.CommonDataKinds.Email.

Использование объектов упрощает запросы. С помощью объекта можно извлечь сразу все данные для контакта или необработанного контакта, вместо того, чтобы сначала делать запрос к родительской таблице для получения идентификатора и последующего запроса к дочерней таблице с использованием полученного идентификатора. Кроме того, поставщик контактов обрабатывает запрос объекта за одну транзакцию, что гарантирует внутреннюю согласованность полученных данных.

Примечание. Объект обычно содержит не все столбцы родительской и дочерней таблиц. Если вы попытаетесь изменить имя столбца, который отсутствует в списке констант имени столбца для объекта, вы получите Exception.

Ниже представлен пример кода для получения всех строк необработанного контакта для контакта. Это фрагмент более крупного приложения, в котором имеются две операции: «основная» и «для получения сведений». Основная операция служит для получения списка строк контактов; при выборе пользователем контакта операция отправляет его идентификатор в операцию для получения сведений. Операция для получения сведений использует объект ContactsContract.Contacts.Entity для отображения всех строк данных, полученных ото всех необработанных контактов, которые связаны с выбранным контактом.

Вот фрагмент кода операции «для получения сведений»:

...
    /*
     * Appends the entity path to the URI. In the case of the Contacts Provider, the
     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
     */
    mContactUri = Uri.withAppendedPath(
            mContactUri,
            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);

    // Initializes the loader identified by LOADER_ID.
    getLoaderManager().initLoader(
            LOADER_ID,  // The identifier of the loader to initialize
            null,       // Arguments for the loader (in this case, none)
            this);      // The context of the activity

    // Creates a new cursor adapter to attach to the list view
    mCursorAdapter = new SimpleCursorAdapter(
            this,                        // the context of the activity
            R.layout.detail_list_item,   // the view item containing the detail widgets
            mCursor,                     // the backing cursor
            mFromColumns,                // the columns in the cursor that provide the data
            mToViews,                    // the views in the view item that display the data
            0);                          // flags

    // Sets the ListView's backing adapter.
    mRawContactList.setAdapter(mCursorAdapter);
...
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    /*
     * Sets the columns to retrieve.
     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
     * DATA1 contains the first column in the data row (usually the most important one).
     * MIMETYPE indicates the type of data in the data row.
     */
    String[] projection =
        {
            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
            ContactsContract.Contacts.Entity.DATA1,
            ContactsContract.Contacts.Entity.MIMETYPE
        };

    /*
     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
     * contact collated together.
     */
    String sortOrder =
            ContactsContract.Contacts.Entity.RAW_CONTACT_ID +
            " ASC";

    /*
     * Returns a new CursorLoader. The arguments are similar to
     * ContentResolver.query(), except for the Context argument, which supplies the location of
     * the ContentResolver to use.
     */
    return new CursorLoader(
            getApplicationContext(),  // The activity's context
            mContactUri,              // The entity content URI for a single contact
            projection,               // The columns to retrieve
            null,                     // Retrieve all the raw contacts and their data rows.
            null,                     //
            sortOrder);               // Sort by the raw contact ID.
}

По завершении загрузки LoaderManager выполняет обратный вызов метода onLoadFinished(). Одним их входящих аргументов для этого метода является Cursor с результатом запроса. В своем приложении вы можете получить данные из этого объекта Cursor для его отображения или дальнейшей работы с ним.

Пакетное изменение

При каждой возможности данные в поставщике контактов следует вставлять, обновлять и удалять в «пакетном режиме» путем создания ArrayList из объектов ContentProviderOperation и вызова метода applyBatch(). Поскольку поставщик контактов выполняет все операции в методе applyBatch() за одну транзакцию, ваши изменения всегда будут находиться в рамках репозитория контактов и всегда будут согласованными. Пакетное изменение также упрощает вставку необработанного контакта одновременно с его подробными данными.

Примечание. Чтобы изменить отдельный необработанный контакт, рекомендуется отправить намерение в приложение для работы с контактами на устройстве вместо обработки изменения в вашем приложении. Более подробно эта операция описана в разделе Получение и изменение данных с помощью намерений.

Пределы

Пакетное изменение большого количества операций может заблокировать выполнение других процессов, что может негативно сказаться на работе пользователя с приложением. Чтобы упорядочить все необходимые изменения в рамках как можно меньшего количества отдельных списков и при этом предотвратить блокирование работы системы, следует задать пределы для одной или нескольких операций. Предел представляет собой объект ContentProviderOperation, в качестве значения параметра isYieldAllowed() которого задано true. При достижении поставщиком контактов предела он приостанавливает свою работу, чтобы могли выполняться другие процессы, и закрывает текущую транзакцию. Когда поставщик запускается снова, он выполняет следующую операцию в ArrayList и запускает новую транзакцию.

Использование пределов позволяет за один вызов метода applyBatch() выполнять более одной транзакции. По этой причине вам следует задать предел для последней операции с набором связанных строк. Например, необходимо задать предел для последней операции в наборе, которая добавляет строки необработанного контакта и связанные с ним строки данных, или для последней операции с набором строк, связанных с одним контактом.

Пределы также являются единицами атомарных операций. Все операции доступа в промежутке между двумя пределами завершаются либо успехом, либо сбоем в рамках одной единицы. Если любой из пределов не задан, наименьшей атомарной операцией считается весь пакет операций. Использование пределов позволяет предотвратить снижение производительности системы и одновременно обеспечить выполнение набора операций на атомарном уровне.

Изменение обратных ссылок

При вставке новой строки необработанного контакта и связанных с ним рядов данных в виде набора объектов ContentProviderOperation вам приходится связывать строки данных со строкой необработанного контакта путем вставки значения android.provider.BaseColumns#_ID необработанного контакта в виде значения RAW_CONTACT_ID. Однако это значение недоступно, когда вы создаетеContentProviderOperation для строки данных, поскольку вы еще не применили ContentProviderOperation для строки необработанного контакта. Чтобы обойти это ограничение, в классе ContentProviderOperation.Builder предусмотрен метод withValueBackReference(). С помощью этого метода можно вставлять или изменять столбец с результатом предыдущей операции.

В методе withValueBackReference() предусмотрено два аргумента:

key
Ключ для пары «ключ-значение». Значением этого аргумента должно быть имя столбца в таблице, которую вы изменяете.
previousResult
Индекс значения, начинающийся с «0», в массиве объектов ContentProviderResult из метода applyBatch(). По мере выполнения пакетных операций результат каждой операции сохраняется в промежуточном массиве результатов. Значением previousResult является индекс одного из этих результатов, который извлекается и хранится со значением key. Благодаря этому можно вставить новую запись необработанного контакта и получить обратно его значение android.provider.BaseColumns#_ID, а затем создать «обратную ссылку» на значение при добавлении строки ContactsContract.Data.

Целиком весь результат создается при первом вызове метода applyBatch(). Размер результата равен размеру ArrayList предоставленных вами объектов ContentProviderOperation. Однако для всех элементов в массиве результатов присваивается значение null, и при попытке воспользоваться обратной ссылкой на результат еще не выполненной операции метод withValueBackReference() выдает Exception.

Ниже представлены фрагменты кода для вставки нового необработанного контакта и его данных в пакетном режиме. Они включают код, который задает предел и использует обратную ссылку. Эти фрагменты представляют собой расширенную версию метода createContacEntry(), который входит в класс ContactAdder в примере приложения Contact Manager.

Первый фрагмент кода служит для извлечения данных контакта из пользовательского интерфейса. На этом этапе пользователь уже выбрал аккаунт, для которого необходимо добавить новый необработанный контакт.

// Creates a contact entry from the current UI values, using the currently-selected account.
protected void createContactEntry() {
    /*
     * Gets values from the UI
     */
    String name = mContactNameEditText.getText().toString();
    String phone = mContactPhoneEditText.getText().toString();
    String email = mContactEmailEditText.getText().toString();

    int phoneType = mContactPhoneTypes.get(
            mContactPhoneTypeSpinner.getSelectedItemPosition());

    int emailType = mContactEmailTypes.get(
            mContactEmailTypeSpinner.getSelectedItemPosition());

В следующем фрагменте кода создается операция для вставки строки необработанного контакта в таблицу ContactsContract.RawContacts:

    /*
     * Prepares the batch operation for inserting a new raw contact and its data. Even if
     * the Contacts Provider does not have any data for this person, you can't add a Contact,
     * only a raw contact. The Contacts Provider will then add a Contact automatically.
     */

     // Creates a new array of ContentProviderOperation objects.
    ArrayList<ContentProviderOperation> ops =
            new ArrayList<ContentProviderOperation>();

    /*
     * Creates a new raw contact with its account type (server type) and account name
     * (user's account). Remember that the display name is not stored in this row, but in a
     * StructuredName data row. No other data is required.
     */
    ContentProviderOperation.Builder op =
            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType())
            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

Затем код создает строки данных для строк отображаемого имени, телефона и адреса эл. почты.

Каждый объект компонента операции использует метод withValueBackReference() для получения RAW_CONTACT_ID. Ссылка возвращается обратно к объекту ContentProviderResult из первой операции, в результате чего добавляется строка необработанного контакта и возвращается его новое значение android.provider.BaseColumns#_ID. После этого каждая строка данных автоматически связывается по своему RAW_CONTACT_ID с новой строкой ContactsContract.RawContacts, которой она принадлежит.

Объект ContentProviderOperation.Builder, который добавляет строку адреса эл. почты, помечается флагом с помощью метода withYieldAllowed(), который задает предел:

    // Creates the display name for the new raw contact, as a StructuredName data row.
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * withValueBackReference sets the value of the first argument to the value of
             * the ContentProviderResult indexed by the second argument. In this particular
             * call, the raw contact ID column of the StructuredName data row is set to the
             * value of the result returned by the first operation, which is the one that
             * actually adds the raw contact row.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to StructuredName
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

            // Sets the data row's display name to the name in the UI.
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

    // Inserts the specified phone number and type as a Phone data row
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Phone
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

            // Sets the phone number and type
            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

    // Inserts the specified email and type as a Phone data row
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Email
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)

            // Sets the email address and type
            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType);

    /*
     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
     * will yield priority to other threads. Use after every set of operations that affect a
     * single contact, to avoid degrading performance.
     */
    op.withYieldAllowed(true);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

В последнем фрагменте кода представлен вызов метода applyBatch() для вставки нового необработанного контакта и его строк данных.

    // Ask the Contacts Provider to create a new contact
    Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" +
            mSelectedAccount.getType() + ")");
    Log.d(TAG,"Creating contact: " + name);

    /*
     * Applies the array of ContentProviderOperation objects in batch. The results are
     * discarded.
     */
    try {

            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
    } catch (Exception e) {

            // Display a warning
            Context ctx = getApplicationContext();

            CharSequence txt = getString(R.string.contactCreationFailure);
            int duration = Toast.LENGTH_SHORT;
            Toast toast = Toast.makeText(ctx, txt, duration);
            toast.show();

            // Log exception
            Log.e(TAG, "Exception encountered while inserting contact: " + e);
    }
}

С помощью пакетных операций можно также реализоватьоптимистическое управление параллелизмом. Это метод применения транзакций изменения без необходимости блокировать базовый репозиторий. Чтобы воспользоваться этим методом, необходимо применить транзакцию и проверить наличие других изменений, которые могли быть внесены в это же время. Если обнаружится, что имеется несогласованное изменение, транзакцию можно откатить и выполнить повторно.

Оптимистическое управление параллелизмом подходит для мобильных устройств, где с системой одновременно взаимодействует только один пользователь, а одновременный доступ к репозиторию данных нескольких пользователей — довольно редкое явление. Поскольку не применяется блокировка, экономится ценное время, которое требуется на установку блокировок или ожидания того, когда другие транзакции отменят свои блокировки.

Ниже представлен порядок использования оптимистического управления параллелизмом при обновлении одной строки ContactsContract.RawContacts.

  1. Извлеките столбец VERSION необработанного контакта, а также другие данные, которые необходимо извлечь.
  2. Создайте объект ContentProviderOperation.Builder, подходящий для применения ограничения, с помощью метода newAssertQuery(Uri). Для URI контента используйте RawContacts.CONTENT_URI, добавив к нему android.provider.BaseColumns#_ID необработанного контакта.
  3. Для объекта ContentProviderOperation.Builder вызовите метод withValue(), чтобы сравнить столбец VERSION с номером версии, которую вы только что получили.
  4. Для того же объекта ContentProviderOperation.Builder вызовите метод withExpectedCount(), чтобы убедиться в том, что проверочное утверждение проверяет только одну строка.
  5. Вызовите метод build(), чтобы создать объект ContentProviderOperation, затем добавьте этот объект в качестве первого объекта в ArrayList, который вы передаете в метод applyBatch().
  6. Примените пакетную транзакцию.

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

В примере кода ниже демонстрируется, как создать assert ContentProviderOperation после запроса одного необработанного контакта с помощью CursorLoader.

/*
 * The application uses CursorLoader to query the raw contacts table. The system calls this method
 * when the load is finished.
 */
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

    // Gets the raw contact's _ID and VERSION values
    mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION));
}

...

// Sets up a Uri for the assert operation
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID);

// Creates a builder for the assert operation
ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri);

// Adds the assertions to the assert operation: checks the version and count of rows tested
assertOp.withValue(SyncColumns.VERSION, mVersion);
assertOp.withExpectedCount(1);

// Creates an ArrayList to hold the ContentProviderOperation objects
ArrayList ops = new ArrayList<ContentProviderOperationg>;

ops.add(assertOp.build());

// You would add the rest of your batch operations to "ops" here

...

// Applies the batch. If the assert fails, an Exception is thrown
try
    {
        ContentProviderResult[] results =
                getContentResolver().applyBatch(AUTHORITY, ops);

    } catch (OperationApplicationException e) {

        // Actions you want to take if the assert operation fails go here
    }

Получение и изменение данных с помощью намерений

С помощью отправки намерения в приложение для работы с контактами, которое имеется на устройстве, можно в обход получить доступ к поставщику контактов. Намерение запускает пользовательский интерфейс приложения на устройстве, посредством которого пользователь может работать с контактами. Такой тип доступа позволяет пользователю выполнять следующие действия:

  • выбор контактов из списка и их возврат в приложение для дальнейшей работы;
  • изменение данных существующего контакта;
  • вставка нового необработанного контакта для любых других аккаунтов;
  • удаление контакта или его данных.

Если пользователь вставляет или обновляет данные , вы можете сначала собрать эти данные, а затем отправить их вместе с намерением.

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

Более подробно общий процесс отправки намерения для получения доступа к поставщику описан в руководстве Основные сведения о поставщике контента в разделе «Доступ к данным посредством намерений». В таблице 4 ниже представлены сводные сведения об операциях, типе MIME и значениях данных, которые используются для доступных задач. Значения дополнительных данных, которые можно использовать для putExtra(), указаны в справочной документации по ContactsContract.Intents.Insert.

Таблица 4. Намерения в поставщике контактов.

Задача Действие Данные Тип MIME Примечания
Выбор контакта из списка ACTION_PICK Одно из следующего:
  • Contacts.CONTENT_URI (отображение списка контактов);
  • Phone.CONTENT_URI (отображение номеров телефонов для необработанного контакта);
  • StructuredPostal.CONTENT_URI (отображение списка почтовых адресов для необработанного контакта);
  • Email.CONTENT_URI (отображение адресов эл. почты для необработанного контакта).
Не используется Отображение списка необработанных контактов или списка данных необработанного контакта (в зависимости от предоставленного URI контента).

Вызовите метод startActivityForResult(), который возвращает URI контента для выбранной строки. URI представлен в форме URI контента таблицы, к которому добавлен LOOKUP_ID строки. Приложение для работы с контактами, установленное на устройстве, делегирует этому URI контента разрешения на чтение и запись, которые действуют в течение всего жизненного цикла вашей операции. Дополнительные сведения представлены в статье Основные сведения о поставщике контента.

Вставка нового необработанного контакта Insert.ACTION Н/Д RawContacts.CONTENT_TYPE, тип MIME для набора необработанных контактов. Отображение экрана Добавить контакт в приложении для работы с контактами, которое установлено на устройстве. Отображаются значения дополнительных данных, добавленных вами в намерение. При отправке с помощью метода startActivityForResult() URI контента нового добавленного необработанного контакта передается обратно в метод обратного вызова onActivityResult() вашей операции в аргументе Intent в поле data. Чтобы получить значение, вызовите метод getData().
Изменение контакта ACTION_EDIT CONTENT_LOOKUP_URI контакта. Операция редактора разрешит пользователю изменить любые данные, связанные с этим контактом. Contacts.CONTENT_ITEM_TYPE, один контакт. Отображение экрана редактирования контакта в приложении для работы с контактами. Отображаются значения дополнительных данных, добавленных вами в намерение. Когда пользователь нажимает на кнопку Готово для сохранения внесенных изменений, ваша операция возвращается на передний план.
Отображение средства выбора, в котором также можно добавлять данные ACTION_INSERT_OR_EDIT Н/Д CONTENT_ITEM_TYPE Это намерение также отображает экран средства выбора приложения для работы с контактами. Пользователь может выбрать контакт для изменения или добавить новый контакт. В зависимости от выбора отображается экран редактирования или добавления контакта, и отображаются дополнительные данные, переданные вами в намерение. Если ваше приложение отображает такие данные контакта, как адрес эл. почты или номер телефона, воспользуйтесь этим намерением, чтобы разрешить пользователю добавлять данные к существующему контакту.

Примечание. Вам не нужно отправлять значение имени в дополнительные данные этого намерения, поскольку пользователь всегда выбирает существующее имя или добавляет новое. Кроме того, если отправить имя, а пользователь решит внести изменения, приложение для работы с контактами отобразит отправленное вами имя, перезаписав предыдущее значение. Если пользователь не заметит этого и сохранит изменения, старое значение будет утеряно.

Приложение для работы с контактами, имеющееся на устройстве, не разрешает вам удалять необработанные контакты или любые его данные с помощью намерений. Вместо этого для обработки необработанного контакта используйте метод ContentResolver.delete() или ContentProviderOperation.newDelete().

Ниже представлен фрагмент кода для создания и отправки намерения, который вставляет новый необработанный контакт и его данные.

// Gets values from the UI
String name = mContactNameEditText.getText().toString();
String phone = mContactPhoneEditText.getText().toString();
String email = mContactEmailEditText.getText().toString();

String company = mCompanyName.getText().toString();
String jobtitle = mJobTitle.getText().toString();

// Creates a new intent for sending to the device's contacts application
Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION);

// Sets the MIME type to the one expected by the insertion activity
insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE);

// Sets the new contact name
insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);

// Sets the new company and job title
insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company);
insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle);

/*
 * Demonstrates adding data rows as an array list associated with the DATA key
 */

// Defines an array list to contain the ContentValues objects for each row
ArrayList<ContentValues> contactData = new ArrayList<ContentValues>();


/*
 * Defines the raw contact row
 */

// Sets up the row as a ContentValues object
ContentValues rawContactRow = new ContentValues();

// Adds the account type and name to the row
rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType());
rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());

// Adds the row to the array
contactData.add(rawContactRow);

/*
 * Sets up the phone number data row
 */

// Sets up the row as a ContentValues object
ContentValues phoneRow = new ContentValues();

// Specifies the MIME type for this data row (all data rows must be marked by their type)
phoneRow.put(
        ContactsContract.Data.MIMETYPE,
        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
);

// Adds the phone number and its type to the row
phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);

// Adds the row to the array
contactData.add(phoneRow);

/*
 * Sets up the email data row
 */

// Sets up the row as a ContentValues object
ContentValues emailRow = new ContentValues();

// Specifies the MIME type for this data row (all data rows must be marked by their type)
emailRow.put(
        ContactsContract.Data.MIMETYPE,
        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
);

// Adds the email address and its type to the row
emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);

// Adds the row to the array
contactData.add(emailRow);

/*
 * Adds the array to the intent's extras. It must be a parcelable object in order to
 * travel between processes. The device's contacts app expects its key to be
 * Intents.Insert.DATA
 */
insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);

// Send out the intent to start the device's contacts app in its add contact activity.
startActivity(insertIntent);

Целостность данных

Поскольку в репозитории контактов содержится важная и конфиденциальная информация, которая, как ожидает пользователь, верна и актуальна, в поставщике контактов предусмотрены четко определенные правила для обеспечения целостности данных. При изменении данных контактов вы обязаны соблюдать эти правила. Вот наиболее важные из этих правил:

Всегда добавляйте строку ContactsContract.CommonDataKinds.StructuredName к каждой добавляемой вами строке ContactsContract.RawContacts.
Если в таблице ContactsContract.Data имеется строка ContactsContract.RawContacts без строки ContactsContract.CommonDataKinds.StructuredName, то могут возникнуть проблемы во время агрегирования.
Всегда связывайте новые строки ContactsContract.Data с их родительскими строками ContactsContract.RawContacts.
Строка ContactsContract.Data, которая не связана с ContactsContract.RawContacts, не будет отображаться в приложении для работы с контактами, имеющемся на устройстве, а также может привести к проблемам с адаптерами синхронизации.
Следует изменять данные только тех необработанных контактов, которыми вы владеете.
Помните о том, что поставщик контактов обычно управляет данными из нескольких аккаунтов различных типов или служб в Интернете. Необходимо убедиться в том, что ваше приложение изменяет или удаляет данные только для тех строк, которые принадлежат вам, а также в том, что оно вставляет данные с использованием только тех типов и имени аккаунта, которыми вы управляете.
Всегда используйте для центров, URI контента, путей URI, имен столбцов, типов MIME и значений TYPE только те константы, которые определены в классе ContactsContract и его подклассах.
Это позволит избежать ошибок. Если какая либо константа устарела, компилятор сообщит об этом с помощью соответствующего предупреждения.

Настраиваемые строки данных

Создав и используя собственные типы MIME, вы можете вставлять, изменять, удалять и извлекать в таблицеContactsContract.Data собственные строки данных. Ваши строки ограничены использованием столбца, который определен в ContactsContract.DataColumns, однако вы можете сопоставить ваши собственные имена столбцов по типам строк с именами столбцов по умолчанию. Данные для ваших строк отображаются в приложении для работы с контактами, которое имеется на устройстве, однако их не удастся изменить или удалить, а также пользователи не смогут добавить дополнительные данные. Чтобы разрешить пользователям изменять ваши настраиваемые строки данных, необходимо реализовать в вашем приложении операцию редактора.

Для отображения настраиваемых данных укажите файл contacts.xml, содержащий элемент <ContactsAccountType> и один или несколько его <ContactsDataKind> дочерних элементов. Дополнительные сведения об этом представлены в разделе <ContactsDataKind> element.

Дополнительные сведения о настраиваемых типах MIME представлены в руководстве Создание поставщика контента.

Адаптеры синхронизации поставщика контактов

Поставщик контактов разработан специально для обработки операций синхронизации данных контактов между устройством и службой в Интернете. Благодаря этому пользователи могут загружать существующие данные на новое устройство и отправлять их в новый аккаунт. Синхронизация также обеспечивает предоставление пользователю всегда актуальных сведений, независимо от источника их добавления и внесенных в них изменений. Еще одно преимущество синхронизации заключается в том, что данные контактов доступны даже в том случае, если устройство не подключено к сети.

Несмотря на множество различных способов реализации синхронизации данных, в системе Android имеется подключаемая платформа синхронизации, которая позволяет автоматизировать выполнение следующих задач:

  • проверка доступности сети;
  • планирование и выполнение синхронизации на основе предпочтений пользователя;
  • перезапуск остановленных процессов синхронизации.

Для использования этой платформы вы предоставляете подключаемый модуль адаптера синхронизации. Каждый адаптер синхронизации является уникальным для службы и поставщика контента, однако способен работать с несколькими аккаунтами в одной службе. В платформе также предусмотрена возможность использовать несколько адаптеров синхронизации для одной и той же службы или поставщика.

Классы и файлы адаптера синхронизации

Адаптер синхронизации реализуется как подкласс класса AbstractThreadedSyncAdapter и устанавливается в составе приложения Android. Система узнает о наличии адаптера синхронизации из элементов в манифесте вашего приложения, а также из особого файла XML, на который имеется указание в манифесте. В файле XML определяются тип аккаунта в онлайн-службе и центр поставщика контента, которые вместе служат уникальными идентификаторами адаптера. Адаптер синхронизации находится в неактивном состоянии до тех пор, пока пользователь не добавит тип аккаунта и не включит синхронизацию с поставщиком контента. На этом этапе система вступает в управление адаптером , при необходимости вызывая его для синхронизации данных между поставщиком контента и сервером.

Примечание. Использование типа аккаунта для идентификации адаптера синхронизации позволяет системе обнаруживать и группировать адаптеры синхронизации, которые обращаются к разным службам из одной и той же организации. Например, у всех адаптеров синхронизации для онлайн-служб Google один и тот же тип аккаунта — com.google. Когда пользователи добавляют на свои устройства аккаунт Google, все установленные адаптеры синхронизации группируются вместе; каждый из адаптеров синхронизируется только с отдельным поставщиком контента на устройстве.

Поскольку в большинстве служб пользователям сначала необходимо подтвердить свою подлинность, прежде чем они смогут получить доступ к данным, система Android предлагает платформу аутентификации, которая аналогична платформе адаптера синхронизации и зачастую используется совместно с ней. Платформа аутентификации использует подключаемые структуры проверки подлинности, которые представляют собой подклассы класса AbstractAccountAuthenticator. Такая структура проверяет подлинность пользователя следующим образом:

  1. Сначала собираются сведения об имени пользователя и его пароле или аналогичная информация (учетные данные пользователя).
  2. Затем учетные данные оправляются в службу.
  3. Наконец, изучается ответ, полученный от службы.

Если служба приняла учетные данные, структура проверки подлинности может сохранить их для использования в дальнейшем. Благодаря использованию структур проверки подлинности AccountManager может предоставить доступ к любым маркерам аутентификации, которые поддерживает структура проверки подлинности и которые она решает предоставить, например, к маркерам аутентификации OAuth2.

Несмотря на то что аутентификация не требуется, она используется большинством служб для работы с контактами. Тем не менее, вам не обязательно использовать платформу аутентификации Android для проверки подлинности.

Реализация адаптера синхронизации

Чтобы реализовать адаптер синхронизации для поставщика контактов, начните с создания приложения Android, которое содержит следующие компоненты.

Компонент Service, который отвечает на запросы системы для привязки к адаптеру синхронизации.
Когда системе требуется запустить синхронизацию, она вызывает метод onBind() службы, чтобы получить объект IBinder для адаптера синхронизации. Благодаря этому система может вызывать методы адаптера между процессами.

В примере адаптера синхронизации именем класса этой службы является com.example.android.samplesync.syncadapter.SyncService.

Адаптер синхронизации, фактически реализованный как конкретный подкласс класса AbstractThreadedSyncAdapter.
Этот класс не подходит для загрузки данных с сервера, отправки данных с устройства и разрешения конфликтов. Основную свою работу адаптер выполняет в методе onPerformSync(). Этот класс допускает создание только одного экземпляра.

В примере адаптера синхронизации адаптер определяется в классе com.example.android.samplesync.syncadapter.SyncAdapter.

Подкласс класса Application.
Этот класс выступает в роли фабрики для единственного экземпляра адаптера синхронизации. Воспользуйтесь методом onCreate(), чтобы создать экземпляр адаптера синхронизации, а затем предоставьте статический метод get, чтобы возвратить единственный экземпляр в метод onBind() службы адаптера синхронизации.
Необязательно: компонент Service, который отвечает на запросы системы для аутентификации пользователей.
AccountManager запускает службу, чтобы начать процесс аутентификации. Метод onCreate() службы создает экземпляр объекта структуры проверки подлинности. Когда системе требуется запустить аутентификацию аккаунта пользователя для адаптера синхронизации приложения, она вызывает метод onBind() службы, чтобы получить объект IBinder для структуры проверки подлинности. Благодаря этому система может вызывать методы структуры проверки подлинности между процессами.

В примере адаптера синхронизации именем класса этой службы является com.example.android.samplesync.authenticator.AuthenticationService.

Необязательно: конкретный подкласс класса AbstractAccountAuthenticator, который обрабатывает запросы на аутентификацию.
В этом классе имеются методы, которые AccountManager вызывает для проверки подлинности учетных данных пользователя на сервере. Подробности процесса аутентификации значительно различаются в зависимости от технологии, используемой на сервере. Чтобы узнать подробнее об аутентификации, обратитесь к соответствующей документации к программному обеспечению используемого сервера.

В примере адаптера синхронизации структура проверки подлинности определяется в классе com.example.android.samplesync.authenticator.Authenticator.

Файлы XML, в которых определяются адаптер синхронизация и структура проверки подлинности для системы.
Описанные ранее компоненты службы адаптера синхронизации и структуры проверки подлинности определяются в элементах <service> в манифесте приложения. Эти элементы включают дочерние элементы <meta-data> , в которых имеются определенные данные для системы.
  • Элемент <meta-data> для службы адаптера синхронизации указывает на файл XML res/xml/syncadapter.xml. В свою очередь, в этом файле задается URI веб-службы для синхронизации с поставщиком контактов, а также тип аккаунта для этой веб-службы.
  • Необязательно: элемент <meta-data> для структуры проверки подлинности указывает на файл XML res/xml/authenticator.xml. В свою очередь, в этом файле задается тип аккаунта, который поддерживает структура проверки подлинности, а также ресурсы пользовательского интерфейса, которые отображаются в процессе аутентификации. Тип аккаунта, указанный в этом элементе, должен совпадать с типом аккаунта, который задан для адаптера синхронизации.

Потоки данных из социальных сетей

Для управления входящими данными из социальных сетей используются таблицы android.provider.ContactsContract.StreamItems и android.provider.ContactsContract.StreamItemPhotos. Можно создать адаптер синхронизации, который добавляет поток данных из вашей собственной сети в эти таблицы, либо вы можете считывать поток данных из этих таблиц и отображать их в собственном приложении. Можно также реализовать оба этих способа. С помощью этих функций вы можете интегрировать службы социальных сетей в компоненты Android для работы с социальными сетями.

Текст из потока данных из социальных сетей

Элементы потока всегда ассоциируются с необработанным контактом. Идентификатор android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID связывается со значением _ID необработанного контакта. Тип аккаунта и его имя для необработанного контакта также хранятся в строке элемента потока.

Данные из потока следует хранить в следующих столбцах:

android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE
Обязательный. Тип аккаунта пользователя для необработанного контакта, связанного с этим элементом потока. Не забудьте задать это значение при вставке элемента потока.
android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME
Обязательный. Имя аккаунта пользователя для необработанного контакта, связанного с этим элементом потока. Не забудьте задать это значение при вставке элемента потока.
Столбцы идентификатора
Обязательный. При вставке элемента потока необходимо вставить указанные ниже столбцы идентификатора.
  • android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID: значение android.provider.BaseColumns#_ID для контакта, с которым ассоциирован этот элемент потока.
  • android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY: значение android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY для контакта, с которым ассоциирован этот элемент потока.
  • android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID: значение android.provider.BaseColumns#_ID для необработанного контакта, с которым ассоциирован этот элемент потока.
android.provider.ContactsContract.StreamItemsColumns#COMMENTS
Необязательный. В нем хранится сводная информация, которую можно отобразить в начале элемента потока.
android.provider.ContactsContract.StreamItemsColumns#TEXT
Текст элемента потока: либо контент, опубликованный источником элемента, либо описание некоторого действия, сгенерировавшего элемент потока. В этом столбце могут содержаться любое форматирование и встроенные изображения ресурсов, рендеринг которых можно выполнить с помощью метода fromHtml(). Поставщик может обрезать слишком длинный контент или заменить его часть многоточием, однако он попытается избежать нарушения тегов.
android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
Текстовая строка с информацией о времени вставки или обновления элемента в миллисекундах от начала отсчета времени. Обслуживанием этого столбца занимаются приложения, которые вставляют или обновляют элементы потока; поставщик контактов не выполняет это автоматически.

Для отображения идентификационной информации для элементов потока воспользуйтесь android.provider.ContactsContract.StreamItemsColumns#RES_ICON, android.provider.ContactsContract.StreamItemsColumns#RES_LABEL и android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE для связывания с ресурсами в вашем приложении.

В таблице android.provider.ContactsContract.StreamItems также имеются столбцы android.provider.ContactsContract.StreamItemsColumns#SYNC1android.provider.ContactsContract.StreamItemsColumns#SYNC4, которые предназначены исключительно для адаптеров синхронизации.

Фотографии из потока данных из социальных сетей

Фотографии, связанные с элементом потока, хранятся в таблице android.provider.ContactsContract.StreamItemPhotos. Столбец android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID в этой таблице связан со столбцом android.provider.BaseColumns#_ID в таблице android.provider.ContactsContract.StreamItems. Ссылки на фотографии хранятся в следующих столбцах таблицы:

Столбец android.provider.ContactsContract.StreamItemPhotos#PHOTO (объект BLOB).
Представление фотографии в двоичном формате и с измененным поставщиком размером для ее хранения и отображения. Этот столбец доступен для обеспечения обратной совместимости с предыдущими версиями поставщика контактов, которые использовались для хранения фотографий. Однако в текущей версии поставщика мы не рекомендуем использовать этот столбец для хранения фотографий. Вместо этого воспользуйтесь столбцом android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID или android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (или обоими столбцами, как описано далее) для хранения фотографий в файле. В этом столбце теперь хранятся миниатюры фотографий, доступных для чтения.
android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
Числовой идентификатор фотографии для необработанного контакта. Добавьте это значение к константе DisplayPhoto.CONTENT_URI, чтобы получить URI контента для одного файла фотографии, а затем вызовите метод openAssetFileDescriptor(), чтобы получить средство обработки файла фотографии.
android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
URI контента, указывающий на файл фотографии, для фотографии, которая представлена этой строкой. Вызовите метод openAssetFileDescriptor(), передав в него этот URI, чтобы получить средство обработки файла фотографии.

Использование таблиц из потока данных из социальных сетей

Эти таблицы работают аналогично другим основным таблицам в поставщике контактов, за исключением указанных ниже моментов.

  • Для работы с этими таблицами требуются дополнительные разрешения на доступ. Для чтения данных из них вашему приложению должно быть предоставлено разрешение android.Manifest.permission#READ_SOCIAL_STREAM. Для изменения таблиц ваше приложение должно иметь разрешение android.Manifest.permission#WRITE_SOCIAL_STREAM.
  • Для таблицы android.provider.ContactsContract.StreamItems существует ограничение на количество строк, которое можно хранить для каждого необработанного контакта. При достижении этого ограничения поставщик контактов освобождает место для новых строк элементов потока путем автоматического удаления строк со самой старой меткой android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP. Чтобы получить это ограничение, запросите URI контента android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI. Для всех аргументов, отличных от URI контента, можно оставить значение null. Запрос возвращает объект Cursor, в котором содержится одна строка с одним столбцом android.provider.ContactsContract.StreamItems#MAX_ITEMS.

Класс android.provider.ContactsContract.StreamItems.StreamItemPhotos определяет дочернюю таблицу объектов android.provider.ContactsContract.StreamItemPhotos, в которой содержатся строки для одного элемента потока.

Взаимодействие с потоками данных из социальных сетей

Управление потоком данных из социальных сетей осуществляется поставщиком контактов совместно с приложением для управления контактами, имеющимся на устройстве. Такой подход позволяет организовать эффективное использование данных из социальных сетей с данными о существующих контактах. Доступны указанные ниже функции.

  • Организовав синхронизацию данных из социальной службы с поставщиком контактов посредством адаптера синхронизации, вы можете получать данные о недавней активности контактов пользователя и хранить такие данные в таблицах ,android.provider.ContactsContract.StreamItems и android.provider.ContactsContract.StreamItemPhotos для использования в дальнейшем.
  • Помимо регулярной синхронизации, адаптер синхронизации можно настроить на получение дополнительных данных при выборе пользователем контакта для просмотра. Благодаря этому ваш адаптер синхронизации может получать фотографии высокого разрешения и самые актуальные элементы потока для контакта.
  • Регистрируя уведомление в приложении для работы с контактами и в поставщике контактов, вы можетеполучать намерения при просмотре контакта и обновлять на этом этапе данные о состоянии контакта из вашей службы. Такой подход может обеспечить большее быстродействие и меньший объем использования полосы пропускания, чем выполнение полной синхронизации с помощью адаптера синхронизации.
  • Пользователи могут добавить контакт в вашу службу социальной сети, обратившись к контакту в приложении для работы с контактами, которое имеется на устройстве. Это реализуется с помощью функции «пригласить контакт», для включения которой используется сочетание операции, которая добавляет существующий контакт в вашу сеть, и файла XML, в котором представлены сведения о вашем приложении для поставщика контактов и приложения для работы с контактами.

Регулярная синхронизация элементов потока с помощью поставщика контактов выполняется так же, как и любая другая синхронизация. Дополнительные сведения о синхронизации представлены в разделе Адаптеры синхронизации поставщика контактов. Регистрация уведомлений и приглашение контактов рассматриваются в следующих двух разделах.

Регистрация для обработки просмотров контактов в социальных сетях

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

  1. В каталоге res/xml/ своего проекта создайте файл contacts.xml. Если у вас уже есть этот файл, переходите к следующему действию.
  2. В этом файле добавьте элемент <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. Если этот элемент уже существует, можете переходить к следующему действию.
  3. Чтобы зарегистрировать службу, которой отправляется уведомление при открытии пользователем страницы со сведениями о контакте в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут viewContactNotifyService="serviceclass" к элементу, где serviceclass — это полное имя класса службы, которая должна получить намерение из приложения для работы с контактами. Для службы-уведомителя используйте класс, который является расширением класса IntentService, чтобы разрешить службе получать намерения. Данные во входящем намерении содержат URI контента необработанного контакта, выбранного пользователем. В службе-уведомителе можно привязать адаптер синхронизации, а затем вызвать его для обновления данных для необработанного контакта.

Чтобы зарегистрировать операцию, которую следует вызвать при выборе пользователем элемента потока или фотографии (или обоих элементов), выполните указанные ниже действия.

  1. В каталоге res/xml/ своего проекта создайте файл contacts.xml. Если у вас уже есть этот файл, переходите к следующему действию.
  2. В этом файле добавьте элемент <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. Если этот элемент уже существует, можете переходить к следующему действию.
  3. Чтобы зарегистрировать одну из ваших операций для обработки выбора пользователем элемента потока в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут viewStreamItemActivity="activityclass" к элементу, где activityclass — это полное имя класса операции, которая должна получить намерение из приложения для работы с контактами.
  4. Чтобы зарегистрировать одну из ваших операций для обработки выбора пользователем фотографии в потоке в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут viewStreamItemPhotoActivity="activityclass" к элементу, где activityclass — это полное имя класса операции, которая должна получить намерение из приложения для работы с контактами.

Дополнительные сведения об элементе <ContactsAccountType> представлены в разделе элемент <ContactsAccountType>.

Данные во входящем намерении содержат URI контента элемента или фотографии, выбранных пользователем. Чтобы использовать разные операции для текстовых элементов и фотографий, используйте оба атрибута в одном файле.

Взаимодействие со службой социальной сети

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

  1. В каталоге res/xml/ своего проекта создайте файл contacts.xml. Если у вас уже есть этот файл, переходите к следующему действию.
  2. В этом файле добавьте элемент <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. Если этот элемент уже существует, можете переходить к следующему действию.
  3. Добавьте следующие атрибуты:
    • inviteContactActivity="activityclass";
    • inviteContactActionLabel="@string/invite_action_label".
    Значение activityclass представляет собой полное имя класса операции, которая должна получить намерение. Значениеinvite_action_label — это текстовая строка, которая отображается в меню Добавить подключение в приложении для работы с контактами.

Примечание. ContactsSource — это устаревшее имя тега для ContactsAccountType, которое больше не используется.

Ссылка contacts.xml

В файле contacts.xml содержатся элементы XML, которые управляют взаимодействием вашего адаптера синхронизации и вашего приложения с поставщиком контактов и приложением для работы с контактами. Эти элементы описаны в следующих разделах.

Элемент <ContactsAccountType>

Элемент <ContactsAccountType> управляет взаимодействием вашего приложения с приложением для работы с контактами. Ниже представлен его синтаксис.

<ContactsAccountType
        xmlns:android="http://schemas.android.com/apk/res/android"
        inviteContactActivity="activity_name"
        inviteContactActionLabel="invite_command_text"
        viewContactNotifyService="view_notify_service"
        viewGroupActivity="group_view_activity"
        viewGroupActionLabel="group_action_text"
        viewStreamItemActivity="viewstream_activity_name"
        viewStreamItemPhotoActivity="viewphotostream_activity_name">

находится в:

res/xml/contacts.xml

может содержать:

<ContactsDataKind>

Описание

Этот элемент объявляет компоненты и элементы пользовательского интерфейса, с помощью которых пользователи могут приглашать свои контакты в социальную сеть, уведомлять пользователей при обновлении одного из их потоков данных из социальных сетей и др.

Обратите внимание, что префикс атрибута android: необязательно использовать для атрибутов <ContactsAccountType>.

Атрибуты

inviteContactActivity
Полное имя класса операции в вашем приложении, которую необходимо активировать при выборе пользователем элемента Добавить подключение в приложении для работы с контактами, которое имеется на устройстве.
inviteContactActionLabel
Текстовая строка, которая отображается для операции, заданной в inviteContactActivity, в меню Добавить подключение. Например, можно указать фразу «Следите за новостями в моей сети». Для этого элемента можно использовать идентификатор строкового ресурса.
viewContactNotifyService
Полное имя класса службы в вашем приложении, которая должна получать уведомления при просмотре контакта пользователем. Такое уведомление отправляется приложением для работы с контактами, которое имеется на устройстве; благодаря этому ваше приложение может отложить выполнение операций, требующих обработки большого объема данных, до тех пор , пока это не потребуется. Например, ваше приложение может реагировать на такое уведомление путем считывания и отображения фотографии контакта в высоком разрешении и самых актуальных элементов потока данных из социальной сети. Дополнительные сведения об этой функции представлены в разделе Взаимодействие с потоками данных из социальных сетей. Пример службы уведомлений представлен в файле NotifierService.java в образце приложенияSampleSyncAdapter.
viewGroupActivity
Полное имя класса операции в вашем приложении, которая может отобразить информацию о группе. При нажатии пользователем на метку группы в приложении для работы с данными, которое имеется на устройстве, отображается пользовательский интерфейс для этой операции.
viewGroupActionLabel
Метка, отображаемая приложением для работы с контактами для элемента пользовательского интерфейса, с помощью которой пользователь может просмотреть группы в вашем приложении.

Например, если вы установили приложение Google+ на ваше устройство и выполняете синхронизацию данных в Google+ с приложением для работы с контактами, то круги Google+ будут обозначены в приложении для работы с контактами как группы на вкладке Группы. При нажатии на на круг Google+ участники крга отобразятся как группа контактов. В верхней части экрана находится значок Google+; если нажать на него, управление перейдет в приложение Google+. В приложении для управления контактами это реализовано с помощью viewGroupActivity, в которой значок Google+ используется в качестве значения viewGroupActionLabel.

Для этого атрибута можно использовать идентификатор строкового ресурса.

viewStreamItemActivity
Полное имя класса операции в вашем приложении, которую запускает приложение для работы с контактами, когда пользователь выбирает элемент потока для необработанного контакта.
viewStreamItemPhotoActivity
Полное имя класса операции в вашем приложении, которую запускает приложение для работы с контактами, когда пользователь выбирает фотографию в элементе потока для необработанного контакта.

Элемент <ContactsDataKind>

Элемент <ContactsDataKind> управляет отображением настраиваемых строк данных вашего приложения в интерфейсе приложения для работы с контактами, которое имеется на устройстве. Ниже представлен его синтаксис.

<ContactsDataKind
        android:mimeType="MIMEtype"
        android:icon="icon_resources"
        android:summaryColumn="column_name"
        android:detailColumn="column_name">

находится в:

<ContactsAccountType>

Описание

Используйте этот элемент для отображения содержимого настраиваемой строки данных в приложении для работы с контактами как части сведений о необработанном контакте. Каждый дочерний элемент <ContactsDataKind> элемента <ContactsAccountType> представляет собой тип настраиваемой строки данных, который адаптер синхронизации добавляет в таблицу ContactsContract.Data. Для каждого используемого вами настраиваемого типа MIME необходимо добавить один элемент <ContactsDataKind>. Вам не нужно добавлять элемент , если у вас имеется настраиваемая строка данных, для которой не требуется отображать данные.

Атрибуты

android:mimeType
Определенные вами настраиваемые типы MIME для одного из ваших типов настраиваемых строк данных в таблице ContactsContract.Data. Например, значение vnd.android.cursor.item/vnd.example.locationstatus может быть настраиваемым типом MIME для строки данных, в которой находятся записи о последнем известном местоположении контакта.
android:icon
Графический ресурс Android, который приложение для работы с контактами отображает рядом с вашими данными. Используйте его для обозначения того, что эти данные получены из вашей службы.
android:summaryColumn
Имя столбца для первого из двух значений, полученных из строки данных. Значение отображается в виде первой строки записи в этой строке данных. Первая строка предназначена для использования в качестве сводных данных, однако она необязательна. См. также android:detailColumn.
android:detailColumn
Имя столбца для второго из двух значений, полученных из строки данных. Значение отображается в виде второй строки записи в этой строке данных. См. также android:summaryColumn.

Дополнительные возможности поставщика контактов

Помимо основных функций, описанных разделах выше, в поставщике контактов предусмотрены указанные ниже полезные функции для работы с данными контактов.

  • Группы контактов
  • Функции работы с фотографиями

Группы контактов

Поставщик контактов может дополнительно отметить коллекции связанных контактов с данными о группе. Если серверу, который связан с учетной записью пользователя, требуется сохранить группы, адаптеру синхронизации для типа этого аккаунта следует передать данные о группах из поставщика контактов на сервер. При добавлении пользователем нового контакта на сервер и последующем помещении этого контакта в новую группу адаптер синхронизации должен добавить эту новую группу в таблицу ContactsContract.Groups. Группа или группы, в которые входит необработанный контакт, хранятся в таблице ContactsContract.Data с использованием типа MIME ContactsContract.CommonDataKinds.GroupMembership.

Если необходимо создать адаптер синхронизации, который будет добавлять данные необработанного контакта с сервера в поставщик контактов, а вы не используете группы, то вам необходимо указать для поставщика, чтобы он сделал ваши данные видимыми. В коде, который выполняется при добавлении пользователем аккаунта на устройство, обновите строку ContactsContract.Settings, которую поставщик контактов добавляет для этого аккаунта. В этой строке укажите в столбце Settings.UNGROUPED_VISIBLE значение «1». После этого поставщик контактов всегда будет делать ваши данные видимыми, даже если вы не используете группы.

Фотографии контактов

В таблице ContactsContract.Data хранятся фотографии в виде строк Photo.CONTENT_ITEM_TYPE типа MIME. Столбец CONTACT_ID в строке связан со столбцом android.provider.BaseColumns#_ID необработанного контакта, которому он принадлежит. Класс ContactsContract.Contacts.Photo определяет вложенную таблицу ContactsContract.Contacts, в которой содержится информация об основной фотографии контакта (которая является основной фотографией основного необработанного контакта этого контакта). Аналогичным образом класс ContactsContract.RawContacts.DisplayPhoto определяет вложенную таблицу ContactsContract.RawContacts, в которой содержится информация об основной фотографии необработанного контакта.

В справочной документации по ContactsContract.Contacts.Photo и ContactsContract.RawContacts.DisplayPhoto содержатся примеры получения информации о фотографии. К сожалению, отсутствует класс для удобного извлечения миниатюры основной фотографии необработанного контакта, однако вы можете отправить запрос в таблицу ContactsContract.Data, выбрать android.provider.BaseColumns#_ID необработанного контакта, Photo.CONTENT_ITEM_TYPE и столбец IS_PRIMARY, чтобы найти строку основной фотографии необработанного контакта.

Потоки данных из социальных сетей также могут включать фотографии. Они находятся в таблице android.provider.ContactsContract.StreamItemPhotos, дополнительные сведения о которой представлены в разделе Фотографии из потока данных из социальных сетей.