| page.title=Поставщик контактов |
| @jd:body |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>Краткое описание</h2> |
| <ul> |
| <li>Репозиторий Android с пользовательскими данными.</li> |
| <li> |
| Синхронизация со службами в Интернете. |
| </li> |
| <li> |
| Интеграция с потоками данных из социальных сетей. |
| </li> |
| </ul> |
| <h2>Содержание документа</h2> |
| <ol> |
| <li> |
| <a href="#InformationTypes">Структура поставщика контактов</a> |
| </li> |
| <li> |
| <a href="#RawContactBasics">Необработанные контакты</a> |
| </li> |
| <li> |
| <a href="#DataBasics">Данные</a> |
| </li> |
| <li> |
| <a href="#ContactBasics">Контакты</a> |
| </li> |
| <li> |
| <a href="#Sources">Данные, полученные от адаптеров синхронизации</a> |
| </li> |
| <li> |
| <a href="#Permissions">Требуемые разрешения</a> |
| </li> |
| <li> |
| <a href="#UserProfile">Профиль пользователя</a> |
| </li> |
| <li> |
| <a href="#ContactsProviderMetadata">Метаданные поставщика контактов</a> |
| </li> |
| <li> |
| <a href="#Access">Доступ к поставщику контактов</a> |
| <li> |
| </li> |
| <li> |
| <a href="#SyncAdapters">Адаптеры синхронизации поставщика контактов</a> |
| </li> |
| <li> |
| <a href="#SocialStream">Потоки данных из социальных сетей</a> |
| </li> |
| <li> |
| <a href="#AdditionalFeatures">Дополнительные возможности поставщика контактов</a> |
| </li> |
| </ol> |
| <h2>Ключевые классы</h2> |
| <ol> |
| <li>{@link android.provider.ContactsContract.Contacts}</li> |
| <li>{@link android.provider.ContactsContract.RawContacts}</li> |
| <li>{@link android.provider.ContactsContract.Data}</li> |
| <li>{@code android.provider.ContactsContract.StreamItems}</li> |
| </ol> |
| <h2>Образцы кода по теме</h2> |
| <ol> |
| <li> |
| <a href="{@docRoot}resources/samples/ContactManager/index.html"> |
| Диспетчер контактов |
| </a> |
| </li> |
| <li> |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> |
| Пример адаптера синхронизации</a> |
| </li> |
| </ol> |
| <h2>См. также:</h2> |
| <ol> |
| <li> |
| <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> |
| Основные сведения о поставщике контента |
| </a> |
| </li> |
| </ol> |
| </div> |
| </div> |
| <p> |
| Поставщик контактов представляет собой эффективный и гибкий компонент Android, который управляет |
| центральным репозиторием устройства, в котором хранятся пользовательские данные. Поставщик контактов — это источник данных, |
| которые отображаются в приложении «Контакты» на вашем устройстве. Вы также можете получить доступ к этим данным в своем собственном |
| приложении и организовать обмен такими данными между устройством и службами в Интернете. Поставщик взаимодействует |
| с широким набором источников данных и пытается организовать управление как можно большим набором данных о каждом человеке, поэтому |
| организация поставщика довольно сложная. По этой причине API поставщика |
| содержит широкий набор классов-контрактов и интерфейсов, отвечающих как за получение данных, так и за их |
| изменение. |
| </p> |
| <p> |
| В этом руководстве рассматриваются следующие вопросы: |
| </p> |
| <ul> |
| <li> |
| основная структура поставщика; |
| </li> |
| <li> |
| порядок получения данных от поставщика; |
| </li> |
| <li> |
| порядок изменения данных в поставщике; |
| </li> |
| <li> |
| порядок записи адаптера синхронизации для синхронизации данных, полученных с вашего сервера, с данными в |
| поставщике контактов. |
| </li> |
| </ul> |
| <p> |
| При изучении данного материала подразумевается, что вы уже знакомы с основами поставщиков контента Android. Дополнительные сведения |
| о поставщиках контента Android представлены в руководстве |
| <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Основные |
| сведения о поставщике контента</a>. Пример |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">адаптера синхронизации</a> |
| служит примером использования такого приложения для обмена данными между поставщиком |
| контактов и приложением, размещенным в веб-службах Google. |
| </p> |
| <h2 id="InformationTypes">Структура поставщика контактов</h2> |
| <p> |
| Поставщик контактов представляет собой поставщик контента Android. Он содержит в себе три типа |
| данных о пользователе, каждый из которых указан в отдельной таблице, предоставляемой поставщиком, |
| как показано на рисунке 1. |
| </p> |
| <img src="{@docRoot}images/providers/contacts_structure.png" alt="" height="364" id="figure1" /> |
| <p class="img-caption"> |
| <strong>Рисунок 1.</strong> Структура таблицы поставщика контактов. |
| </p> |
| <p> |
| В качестве имен этих трех таблиц обычно используются названия соответствующих классов-контрактов. Эти классы |
| определяют константы для URI контента, названий столбцов и значений в столбцах этих таблиц. |
| </p> |
| <dl> |
| <dt> |
| Таблица {@link android.provider.ContactsContract.Contacts} |
| </dt> |
| <dd> |
| Строки в этой таблице содержат данные о разных пользователях, полученные путем агрегации строк необработанных контактов. |
| </dd> |
| <dt> |
| Таблица {@link android.provider.ContactsContract.RawContacts} |
| </dt> |
| <dd> |
| Строки в этой таблице содержат сводные данные о пользователе, относящиеся к пользовательскому аккаунту и его типу. |
| </dd> |
| <dt> |
| Таблица {@link android.provider.ContactsContract.Data} |
| </dt> |
| <dd> |
| Строки в этой таблице содержат сведения о необработанных контактах, такие как адреса эл. почты или номера телефонов. |
| </dd> |
| </dl> |
| <p> |
| Другие таблицы, представленные классами-контрактами в {@link android.provider.ContactsContract}, |
| представляют собой вспомогательные таблицы, которые поставщик контактов использует для управления своими операциями или поддержки |
| определенных функций, имеющихся в приложении устройства «Контакты» или приложениях для телефонной связи. |
| </p> |
| <h2 id="RawContactBasics">Необработанные контакты</h2> |
| <p> |
| Необработанный контакт представляет собой данные о пользователе, поступающие из одного аккаунта определенного |
| типа. Поскольку в качестве источника данных о пользователе в поставщике контактов может выступать сразу несколько онлайн-служб, |
| для одного и того же пользователя в поставщике контактов может существовать несколько необработанных контактов. |
| Это также позволяет пользователю объединять пользовательские данные из нескольких аккаунтов |
| одного и того же типа. |
| </p> |
| <p> |
| Большая часть данных необработанного контакта не хранится в таблице |
| {@link android.provider.ContactsContract.RawContacts}. Вместо этого они хранятся в одной или нескольких |
| строках в таблице {@link android.provider.ContactsContract.Data}. В каждой строке данных имеется |
| столбец {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID}, |
| в котором содержится значение {@code android.provider.BaseColumns#_ID RawContacts._ID} его |
| родительской строки{@link android.provider.ContactsContract.RawContacts}. |
| </p> |
| <h3 id="RawContactsColumns">Важные столбцы необработанных контактов</h3> |
| <p> |
| В таблице 1 указаны столбцы таблицы {@link android.provider.ContactsContract.RawContacts}, |
| которые имеют большое значение. Обязательно ознакомьтесь с примечаниями, приведенными после этой таблицы. |
| </p> |
| <p class="table-caption" id="table1"> |
| <strong>Таблица 1.</strong> Важные столбцы необработанных контактов. |
| </p> |
| <table> |
| <tr> |
| <th scope="col">Название столбца</th> |
| <th scope="col">Использование</th> |
| <th scope="col">Примечания</th> |
| </tr> |
| <tr> |
| <td> |
| {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME} |
| </td> |
| <td> |
| Имя аккаунта для типа аккаунта, который выступает в роли источника данных для необработанного контакта. |
| Например, имя аккаунта Google является одним из эл. адресов почты Gmail |
| владельца устройства. Дополнительные сведения |
| см. в следующей записи |
| {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE}. |
| </td> |
| <td> |
| Формат этого имени зависит от типа аккаунта. Это не обязательно |
| адрес эл. почты. |
| </td> |
| </tr> |
| <tr> |
| <td> |
| {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} |
| </td> |
| <td> |
| Тип аккаунта, который выступает в роли источника данных для необработанного контакта. Например, тип аккаунта |
| Google — <code>com.google</code>. Всегда указывайте тип аккаунта |
| и идентификатор домена, которым вы владеете или управляете. Это позволит гарантировать уникальность |
| типа вашего аккаунта. |
| </td> |
| <td> |
| У типа аккаунта, выступающего в роли источника данных контактов, обычно имеется связанный с ним адаптер синхронизации, |
| который синхронизирует данные с поставщиком контактов. |
| </tr> |
| <tr> |
| <td> |
| {@link android.provider.ContactsContract.RawContactsColumns#DELETED} |
| </td> |
| <td> |
| Флаг deleted для необработанного контакта. |
| </td> |
| <td> |
| Этот флаг позволяет поставщику контактов хранить строку внутри себя до тех пор, |
| пока адаптеры синхронизации не смогут удалить эту строку с серверов, а затем |
| удалить ее из репозитория. |
| </td> |
| </tr> |
| </table> |
| <h4>Примечания</h4> |
| <p> |
| Ниже представлены важные примечания к таблице |
| {@link android.provider.ContactsContract.RawContacts}. |
| </p> |
| <ul> |
| <li> |
| Имя необработанного контакта не хранится в его строке в таблице |
| {@link android.provider.ContactsContract.RawContacts}. Вместо этого оно хранится в |
| таблице {@link android.provider.ContactsContract.Data} |
| в строке {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}. У необработанного контакта |
| имеется в таблице {@link android.provider.ContactsContract.Data} только одна строка такого типа. |
| </li> |
| <li> |
| <strong>Внимание!</strong> Чтобы использовать в строке необработанного контакта данные собственного аккаунта, строку |
| , сначала необходимо зарегистрировать его в классе {@link android.accounts.AccountManager}. Для этого предложите |
| пользователям добавить тип аккаунта и его имя в список аккаунтов. Если |
| не сделать этого, поставщик контактов автоматически удалит вашу строку необработанного контакта. |
| <p> |
| Например, если необходимо, чтобы в вашем приложении хранились данные контактов для веб-службы |
| в домене {@code com.example.dataservice}, и аккаунт пользователя службы |
| выглядит следующим образом:{@code becky.sharp@dataservice.example.com}, то пользователю сначала необходимо добавить |
| «тип» аккаунта ({@code com.example.dataservice}) и его «имя» |
| ({@code becky.smart@dataservice.example.com}) прежде чем ваше приложение сможет добавлять строки необработанных контактов. |
| Это требование можно указать в документации для пользователей, а также можно предложить |
| пользователю добавить тип и имя своего аккаунта, либо реализовать оба этих варианта. Более подробно типы и имена аккаунтов |
| рассматриваются в следующем разделе. |
| </li> |
| </ul> |
| <h3 id="RawContactsExample">Источники данных необработанных контактов</h3> |
| <p> |
| Чтобы понять, что такое необработанный контакт, рассмотрим пример с пользователем Emily Dickinson, на устройстве которой имеется три |
| следующих аккаунта: |
| </p> |
| <ul> |
| <li><code>emily.dickinson@gmail.com</code>;</li> |
| <li><code>emilyd@gmail.com</code>;</li> |
| <li>Аккаунт belle_of_amherst в Twitter</li> |
| </ul> |
| <p> |
| Она включила функцию <em>Синхронизировать контакты</em> для всех трех этих аккаунтов |
| в настройках <em>Аккаунты</em>. |
| </p> |
| <p> |
| Предположим, что Emily Dickinson открывает браузер, входит в Gmail под именем |
| <code>emily.dickinson@gmail.com</code>, затем открывает |
| Контакты и добавляет новый контакт Thomas Higginson. Позже она снова входит в Gmail под именем |
| <code>emilyd@gmail.com</code> и отправляет письмо пользователю Thomas Higginson, который автоматически |
| добавляется в ее контакты. Также она подписана на новости от colonel_tom (аккаунт пользователя Thomas Higginson в Twitter) в |
| Twitter. |
| </p> |
| <p> |
| В результате этих действий поставщик контактов создает три необработанных контакта: |
| </p> |
| <ol> |
| <li> |
| Необработанный контакт Thomas Higginson связан с аккаунтом <code>emily.dickinson@gmail.com</code>. |
| Тип этого аккаунта — Google. |
| </li> |
| <li> |
| Второй необработанный контакт Thomas Higginson связан с аккаунтом <code>emilyd@gmail.com</code>. |
| Тип этого аккаунта — также Google. Второй необработанный контакт создается даже в том случае, |
| если его имя полностью совпадает с именем предыдущего контакта, поскольку первый |
| был добавлен для другого аккаунта. |
| </li> |
| <li> |
| Третий необработанный контакт Thomas Higginson связан с аккаунтом belle_of_amherst. Тип этого аккаунта |
| — Twitter. |
| </li> |
| </ol> |
| <h2 id="DataBasics">Данные</h2> |
| <p> |
| Как уже указывалось ранее, данные необработанного контакта |
| хранятся в строке {@link android.provider.ContactsContract.Data}, которая связана со значением |
| <code>_ID</code> необработанного контакта. Благодаря этому для одного необработанного контакта может существовать несколько экземпляров |
| одного и того же типа данных (например, адресов эл. почты или номеров телефонов). Например, если у контакта |
| Thomas Higginson для аккаунта {@code emilyd@gmail.com} (строка необработанного контакта Thomas Higginson, |
| связанная с учетной записью Google <code>emilyd@gmail.com</code>) имеется адрес эл. почты |
| <code>thigg@gmail.com</code> и служебный адрес эл. почты |
| <code>thomas.higginson@gmail.com</code>, то поставщик контактов сохраняет две строки |
| адреса эл. почты и связывает их с этим необработанным контактом. |
| </p> |
| <p> |
| Обратите внимание, что в этой таблице хранятся данные разных типов. Строки со сведениями об отображаемом имени, |
| номере телефона, адресе эл. почты, почтовом адресе, фото и веб-сайте хранятся в таблице |
| {@link android.provider.ContactsContract.Data}. Для упрощения управления этими данными в таблице |
| {@link android.provider.ContactsContract.Data} предусмотрены столбцы с описательными именами, |
| а также другие столбцы с универсальными именами. Содержимое в столбце с описательным именем имеет то же значение, |
| независимо от типа данных в строке, тогда как содержимое столбца с универсальным именем |
| может иметь разное значение в зависимости от типа данных. |
| </p> |
| <h3 id="DescriptiveColumns">Описательные имена столбцов</h3> |
| <p> |
| Вот некоторые примеры столбцов с описательными именами: |
| </p> |
| <dl> |
| <dt> |
| {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID} |
| </dt> |
| <dd> |
| Значение в столбце <code>_ID</code> необработанного контакта для этих данных. |
| </dd> |
| <dt> |
| {@link android.provider.ContactsContract.Data#MIMETYPE} |
| </dt> |
| <dd> |
| Тип данных, хранящихся в этой строке, в виде настраиваемого типа MIME. Поставщик контактов |
| использует типы MIME, заданные в подклассах класса |
| {@link android.provider.ContactsContract.CommonDataKinds}. Эти типы MIME являются открытыми, и |
| их может использовать любое приложение или адаптер синхронизации, поддерживающие работу с поставщиком контактов. |
| </dd> |
| <dt> |
| {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} |
| </dt> |
| <dd> |
| Если этот тип данных для необработанного контакта встречается несколько раз, то |
| столбец {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} помечает флагом |
| строки данных, в которых содержатся основные данные для этого типа. Например, если |
| пользователь нажал и удерживает номер телефона контакта и выбрал параметр <strong>Использовать по умолчанию</strong>, |
| то в столбце {@link android.provider.ContactsContract.Data} с этим номером телефона |
| в соответствующем столбце {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} задается |
| значение, отличное от нуля. |
| </dd> |
| </dl> |
| <h3 id="GenericColumns">Универсальные имена столбцов</h3> |
| <p> |
| Существует 15 общедоступных столбцов с универсальными именами (<code>DATA1</code>–<code>DATA15</code>) |
| и четыре дополнительных столбца |
| (<code>SYNC1</code>–<code>SYNC4</code>), которые используются только адаптерами |
| синхронизации. Константы столбцов с универсальными именами применяются всегда, независимо от типа данных, |
| содержащихся в столбце. |
| </p> |
| <p> |
| Столбец <code>DATA1</code> является индексируемым. Поставщик контактов всегда использует этот столбец для |
| данных, которые, как он ожидает, будут наиболее часто являться целевыми в запросах. Например, |
| в строке с адресами эл. почты в этом столбце указывается фактический адрес эл. почты. |
| </p> |
| <p> |
| Обычно столбец <code>DATA15</code> зарезервирован для данных больших двоичных объектов |
| (BLOB), таких как миниатюры фотографий. |
| </p> |
| <h3 id="TypeSpecificNames">Имена столбцов по типам строк</h3> |
| <p> |
| Для упрощения работы со столбцами определенного типа строк в поставщике контактов |
| также предусмотрены константы для имен столбцов по типам строк, которые определены в подклассах класса |
| {@link android.provider.ContactsContract.CommonDataKinds}. Эти константы просто |
| присваивают одному и тому же имени столбца различные константы, что позволяет вам получать доступ к данным в строке |
| определенного типа. |
| </p> |
| <p> |
| Например, класс {@link android.provider.ContactsContract.CommonDataKinds.Email} определяет |
| константы имени столбца для строки {@link android.provider.ContactsContract.Data}, |
| в которой имеется тип MIME |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE |
| Email.CONTENT_ITEM_TYPE}. В этом классе содержится константа |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} для столбца адреса |
| эл. почты. Фактическое значение |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} — data1, которое совпадает |
| с универсальным именем столбца. |
| </p> |
| <p class="caution"> |
| <strong>Внимание!</strong> Не добавляйте свои настраиваемые данные в таблицу |
| {@link android.provider.ContactsContract.Data} с помощью строки, в которой имеется один из |
| предварительно заданных поставщиком типов MIME. В противном случае вы можете потерять данные или вызвать неполадки |
| в работе поставщика. Например, не следует добавлять строку с типом MIME |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE |
| Email.CONTENT_ITEM_TYPE}, в которой в столбце |
| <code>DATA1</code> вместо адреса эл. почты содержится имя пользователя. Если вы укажете в строке собственный настраиваемый тип MIME, вы можете свободно |
| указывать собственные имена столбцов по типам строк и использовать их так, как пожелаете. |
| </p> |
| <p> |
| На рисунке 2 показано, как столбцы с описательными именами и столбцы данных отображаются в строке |
| {@link android.provider.ContactsContract.Data}, а также как имена столбцов по типу строк «накладываются» |
| на универсальные имена столбцов. |
| </p> |
| <img src="{@docRoot}images/providers/data_columns.png" alt="How type-specific column names map to generic column names" height="311" id="figure2" /> |
| <p class="img-caption"> |
| <strong>Рисунок 2.</strong> Имена столбцов по типам строк и универсальные имена столбцов. |
| </p> |
| <h3 id="ColumnMaps">Классы имен столбцов по типам строк</h3> |
| <p> |
| В таблице 2 перечислены наиболее часто используемые классы имен столбцов по типам строк. |
| </p> |
| <p class="table-caption" id="table2"> |
| <strong>Таблица 2.</strong> Классы имен столбцов по типам строк</p> |
| <table> |
| <tr> |
| <th scope="col">Класс сопоставления</th> |
| <th scope="col">Тип данных</th> |
| <th scope="col">Примечания</th> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredName}</td> |
| <td>Данные об имени необработанного контакта, связанного с этой строкой данных.</td> |
| <td>У необработанного контакта имеется только одна строка такого типа.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.Photo}</td> |
| <td>Основная фотография необработанного контакта, связанного с этой строкой данных.</td> |
| <td>У необработанного контакта имеется только одна строка такого типа.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.Email}</td> |
| <td>Адрес эл. почты необработанного контакта, связанного с этой строкой данных.</td> |
| <td>У необработанного контакта может быть несколько адресов эл. почты.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal}</td> |
| <td>Почтовый адрес необработанного контакта, связанного с этой строкой данных.</td> |
| <td>У необработанного контакта может быть несколько почтовых адресов.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}</td> |
| <td>Идентификатор, с помощью которого необработанный контакт связан с одной из групп в поставщике контактов.</td> |
| <td> |
| Группы представляют собой необязательный компонент для типа аккаунта и имени аккаунта. Дополнительные сведения о |
| группах представлены в разделе <a href="#Groups">Группы контактов</a>. |
| </td> |
| </tr> |
| </table> |
| <h3 id="ContactBasics">Контакты</h3> |
| <p> |
| Поставщик контактов объединяет строки с необработанными контактами для всех типов аккаунтов и имен аккаунтов |
| для создания <strong>контакта</strong>. Это позволяет упростить отображение и изменение всех данных, |
| собранных в отношении пользователя. Поставщик контактов управляет процессом создания строк |
| контактов и агрегированием необработанных контактов, у которых имеется строка контакта. Ни приложениям, ни |
| адаптерам синхронизации не разрешается добавлять контакты, а некоторые столбцы в строке контакта доступны только для чтения. |
| </p> |
| <p class="note"> |
| <strong>Примечание.</strong> Если попытаться добавить контакт в поставщик контактов с помощью метода |
| {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()}, будет выдано исключение |
| {@link java.lang.UnsupportedOperationException}. Если вы попытаетесь обновить столбец, |
| доступный только для чтения, это действие будет проигнорировано. |
| </p> |
| <p> |
| При добавлении нового необработанного контакта, |
| который не соответствует ни одному из существующих контактов, поставщик контактов создает новый контакт. Поставщик поступает аналогично в случае, если |
| данные в строке существующего необработанного контакта изменяются таким образом, что они больше не соответствуют контакту, |
| с которым они ранее были связаны. При создании приложением или адаптером синхронизации нового контакта, |
| который <em></em> соответствует существующему контакту, то новый контакт объединяется с |
| существующим контактом. |
| </p> |
| <p> |
| Поставщик контактов связывает строку контакта с его строками необработанного контакта посредством столбца |
| <code>_ID</code> строки контакта в таблице |
| {@link android.provider.ContactsContract.Contacts Contacts}. Столбец <code>CONTACT_ID</code> в таблице необработанных контактов |
| {@link android.provider.ContactsContract.RawContacts} содержит значения <code>_ID</code> для |
| строки контактов, связанной с каждой строкой необработанных контактов. |
| </p> |
| <p> |
| В таблице {@link android.provider.ContactsContract.Contacts} также имеется столбец |
| {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}, который выступает в роли |
| «постоянной ссылки» на строку контакта. Поскольку поставщик контактов автоматически сохраняет контакты, |
| в ответ на агрегирование или синхронизацию он может изменить значение {@code android.provider.BaseColumns#_ID} |
| строки контакта. Даже если это произойдет, URI контента |
| {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, объединенный с |
| {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} контакта, будет |
| по-прежнему указывать на строку контакта, поэтому вы можете смело использовать |
| {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} |
| для сохранения ссылок на «избранные» контакты и др. Столбец имеет собственный формат, |
| который не связан с форматом столбца{@code android.provider.BaseColumns#_ID}. |
| </p> |
| <p> |
| На рисунке 3 показаны взаимосвязи этих трех основных таблиц друг с другом. |
| </p> |
| <img src="{@docRoot}images/providers/contacts_tables.png" alt="Contacts provider main tables" height="514" id="figure4" /> |
| <p class="img-caption"> |
| <strong>Рисунок 3</strong>. Взаимосвязи между таблицами контактов, необработанных контактов и сведений. |
| </p> |
| <h2 id="Sources">Данные, полученные от адаптеров синхронизации</h2> |
| <p> |
| Пользователь вводит данные контактов прямо на устройстве, однако данные также поступают в поставщик контактов |
| из веб-служб посредством <strong>адаптеров синхронизации</strong>, что позволяет автоматизировать |
| обмен данными между устройством и службами в Интернете. Адаптеры синхронизации выполняются в фоновом режиме под |
| управлением системы, и для управления данными они вызывают методы |
| {@link android.content.ContentResolver}. |
| </p> |
| <p> |
| В Android веб-служба, с которой работает адаптер синхронизации, определяется по типу аккаунта. |
| Каждый адаптер синхронизации работает с одним типом аккаунта, однако он может поддерживать несколько имен аккаунтов |
| такого типа. Вкратце типы и имена аккаунтов рассматриваются |
| в разделе <a href="#RawContactsExample">Источники данных необработанных контактов</a>. Указанные ниже определения позволяют |
| более точно охарактеризовать связь между типами и именами аккаунтов и адаптерами синхронизации и службами. |
| </p> |
| <dl> |
| <dt> |
| Тип аккаунта |
| </dt> |
| <dd> |
| Определяет службу, в которой пользователь хранит данные. В большинстве случаев для работы со |
| службой пользователю необходимо пройти проверку подлинности. Например, Google Контакты представляет собой тип аккаунтов, обозначаемый кодом |
| <code>google.com</code>. Это значение соответствует типу аккаунта, используемого |
| {@link android.accounts.AccountManager}. |
| </dd> |
| <dt> |
| Имя аккаунта |
| </dt> |
| <dd> |
| Определяет конкретный аккаунт или имя для входа для типа аккаунта. Аккаунты «Контакты Google» |
| — это то же, что и аккаунты Google, в качестве имени которых используется адрес эл. почты. |
| В других службах может использоваться имя пользователя, состоящее из одного слова, или числовой идентификатор. |
| </dd> |
| </dl> |
| <p> |
| Типы аккаунтов не обязательно должны быть уникальными. Пользователь может создать несколько аккаунтов Google Контакты |
| и загрузить данные из них в поставщик контактов; это может произойти в случае, если у пользователя имеется один набор |
| персональных контактов для личного аккаунта, и другой набор — для служебного аккаунта. Имена |
| аккаунтов обычно уникальные. Вместе они формируют определенный поток данных между поставщиком контактов |
| и внешними службами. |
| </p> |
| <p> |
| Если необходимо передать данные из службы в поставщик контактов, необходимо создать |
| собственный адаптер синхронизации. Дополнительные сведения об этом представлены в разделе |
| <a href="#SyncAdapters">Адаптеры синхронизации поставщика контактов</a>. |
| </p> |
| <p> |
| На рисунке 4 показано, какую роль выполняет поставщик контактов в потоке передачи данных |
| о пользователях. В области, отмеченной на рисунке как sync adapters, каждый адаптер промаркирован в соответствии с поддерживаемым им типом аккаунтов. |
| </p> |
| <img src="{@docRoot}images/providers/ContactsDataFlow.png" alt="Flow of data about people" height="252" id="figure5" /> |
| <p class="img-caption"> |
| <strong>Рисунок 4</strong>. Поток передачи данных через поставщика контактов. |
| </p> |
| <h2 id="Permissions">Требуемые разрешения</h2> |
| <p> |
| Приложения, которым требуется доступ к поставщику контактов, |
| должны запросить указанные ниже разрешения. |
| </p> |
| <dl> |
| <dt>Доступ на чтение одной или нескольких таблиц</dt> |
| <dd> |
| {@link android.Manifest.permission#READ_CONTACTS}, указанный в файле |
| <code>AndroidManifest.xml</code> с элементом |
| <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> |
| <uses-permission></a></code> в виде |
| <code><uses-permission android:name="android.permission.READ_CONTACTS"></code>. |
| </dd> |
| <dt>Доступ на запись в одну или несколько таблиц</dt> |
| <dd> |
| {@link android.Manifest.permission#WRITE_CONTACTS}, указанный в файле |
| <code>AndroidManifest.xml</code> с элементом |
| <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> |
| <uses-permission></a></code> в виде |
| <code><uses-permission android:name="android.permission.WRITE_CONTACTS"></code>. |
| </dd> |
| </dl> |
| <p> |
| Эти разрешения не распространяются на работу с данными профиля пользователя. Профиль пользователя |
| и требуемые разрешения для работы с ним рассматриваются в разделе |
| <a href="#UserProfile">Профиль пользователя</a> ниже. |
| </p> |
| <p> |
| Помните, что данные о контактах пользователя являются личными и конфиденциальными. Пользователи заботятся о своей конфиденциальности, |
| поэтому не хотят, чтобы приложения собирали данные о них самих или их контактах. |
| Если пользователю не до конца ясно, для чего требуется разрешение на доступ к данным контактов, они могут присвоить |
| вашему приложению низкий рейтинг или вообще откажутся его устанавливать. |
| </p> |
| <h2 id="UserProfile">Профиль пользователя</h2> |
| <p> |
| В таблице {@link android.provider.ContactsContract.Contacts} имеется всего одна строка, содержащая |
| данные профиля для устройства пользователя. Эти данные описывают <code>user</code> устройства, |
| а не один из контактов пользователя. Строка контактов профиля связана со строкой |
| необработанных контактов в каждой из систем, в которой используется профиль. |
| В каждой строке необработанного контакта профиля может содержаться несколько строк данных. Константы для доступа к профилю пользователя |
| представлены в классе {@link android.provider.ContactsContract.Profile}. |
| </p> |
| <p> |
| Для доступа к профилю пользователя требуются особые разрешения. Кроме разрешений |
| {@link android.Manifest.permission#READ_CONTACTS} и |
| {@link android.Manifest.permission#WRITE_CONTACTS}, которые требуются для чтения и записи, для доступа к профилю пользователя необходимы разрешения |
| {@code android.Manifest.permission#READ_PROFILE} и |
| {@code android.Manifest.permission#WRITE_PROFILE} |
| на чтение и запись соответственно. |
| </p> |
| <p> |
| Всегда следует помнить, что профиль пользователя представляет собой конфиденциальную информацию. Разрешение |
| {@code android.Manifest.permission#READ_PROFILE} предоставляет вам доступ к личной информации на устройстве |
| пользователя. В описании своего приложения обязательно укажите, для |
| чего вам требуется доступ к профилю пользователя. |
| </p> |
| <p> |
| Чтобы получить строку контакта с профилем пользователя, вызовите метод |
| {@link android.content.ContentResolver#query(Uri,String[], String, String[], String) |
| ContentResolver.query()}. Задайте для URI контента значение |
| {@link android.provider.ContactsContract.Profile#CONTENT_URI} и не указывайте никаких критериев |
| выборки. Этот URI контента также можно использовать в качестве основного URI для получения |
| необработанных контактов или данных профиля. Ниже представлен фрагмент кода для получения данных профиля. |
| </p> |
| <pre> |
| // 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); |
| </pre> |
| <p class="note"> |
| <strong>Примечание.</strong> Если при извлечении несколько строк контактов необходимо определить, |
| какой из них является профилем пользователя, обратитесь к столбцу |
| {@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} этой строки. Если в этом столбце |
| указано значение «1», то в это строке находится профиль пользователя. |
| </p> |
| <h2 id="ContactsProviderMetadata">Метаданные поставщика контактов</h2> |
| <p> |
| Поставщик контактов управляет данными, которые используются для отслеживания состояния данных контакта в |
| репозитории. Эти метаданные о репозитории хранятся в различных местах, включая |
| строки необработанных контактов, данные и строки таблицы контактов, таблицу |
| {@link android.provider.ContactsContract.Settings} и таблицу |
| {@link android.provider.ContactsContract.SyncState}. В таблице ниже |
| указаны значения каждого из этих фрагментов метаданных. |
| </p> |
| <p class="table-caption" id="table3"> |
| <strong>Таблица 3.</strong> Метаданные в поставщике контактов</p> |
| <table> |
| <tr> |
| <th scope="col">Таблица</th> |
| <th scope="col">Столбец</th> |
| <th scope="col">Значения</th> |
| <th scope="col">Описание</th> |
| </tr> |
| <tr> |
| <td rowspan="2">{@link android.provider.ContactsContract.RawContacts}</td> |
| <td rowspan="2">{@link android.provider.ContactsContract.SyncColumns#DIRTY}</td> |
| <td>«0» — с момента последней синхронизации изменения не вносились.</td> |
| <td rowspan="2"> |
| Служит для отметки необработанных контактов, которые были изменены на устройстве и которые необходимо снова синхронизировать с |
| сервером. Значение устанавливается автоматически поставщиком контактов при обновлении строк приложениями |
| Android. |
| <p> |
| Адаптеры синхронизации, которые вносят изменения в необработанные контакты или таблицы данных, должны всегда добавлять к используемому ими URI |
| контента строку |
| {@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER}. Это позволяет предотвратить пометку таких строк поставщиком как «грязных». |
| В противном случае изменения, внесенные адаптером синхронизации, будут рассматриваться как локальные изменения, |
| которые подлежат отправке на сервер, даже если источником таких изменений был сам сервер. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td>«1» — с момента последней синхронизации были внесены изменения, которые необходимо отразить и на сервере.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.RawContacts}</td> |
| <td>{@link android.provider.ContactsContract.SyncColumns#VERSION}</td> |
| <td>Номер версии этой строки.</td> |
| <td> |
| Поставщик контактов автоматически увеличивает это значение при каждом |
| изменении в строке или в связанных с ним данных. |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.Data}</td> |
| <td>{@link android.provider.ContactsContract.DataColumns#DATA_VERSION}</td> |
| <td>Номер версии этой строки.</td> |
| <td> |
| Поставщик контактов автоматически увеличивает это значение при каждом |
| изменении в строке данных. |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.RawContacts}</td> |
| <td>{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}</td> |
| <td> |
| Строковое значение, которое служит уникальным идентификатором данного необработанного контакта в аккаунте, |
| в котором он был создан. |
| </td> |
| <td> |
| Когда адаптер синхронизации создает новый необработанный контакт, в этом столбце следует указать |
| уникальный идентификатор этого необработанного контакта на сервере. Когда же приложение Android создает |
| новый необработанный контакт, то приложению следует оставить этот столбец пустым. Это служит сигналом для |
| адаптера синхронизации, чтобы создать новый необработанный контакт на сервере и |
| получить значение {@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}. |
| <p> |
| В частности, идентификатор источника должен быть <strong>уникальным</strong> для каждого типа аккаунта |
| и неизменным при синхронизации. |
| </p> |
| <ul> |
| <li> |
| Уникальный: у каждого необработанного контакта для аккаунта должен быть свой собственный идентификатор источника. Если |
| не применить это требование, у вас обязательно возникнут проблемы с приложением «Контакты». |
| Обратите внимание, что два необработанных контакта одного и того же <em>типа</em> аккаунта могут |
| иметь одинаковый идентификатор источника. Например, необработанный контакт Thomas Higginson для |
| аккаунта {@code emily.dickinson@gmail.com} может иметь такой же |
| идентификатор источника, что и контакт Thomas Higginson для аккаунта |
| {@code emilyd@gmail.com}. |
| </li> |
| <li> |
| Стабильный: идентификаторы источников представляют собой неизменную часть данных онлайн-службы для |
| необработанного контакта. Например, если пользователь выполняет повторную синхронизацию после очистки хранилища контактов в |
| настройках приложения, идентификаторы источников восстановленных необработанных контактов должны быть такими же, |
| как и прежде. Если не применить это требование, перестанут |
| работать ярлыки. |
| </li> |
| </ul> |
| </td> |
| </tr> |
| <tr> |
| <td rowspan="2">{@link android.provider.ContactsContract.Groups}</td> |
| <td rowspan="2">{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE}</td> |
| <td>«0» — контакты, представленные в этой группе, не должны отображаться в интерфейсах пользователя приложений Android.</td> |
| <td> |
| Этот столбец предназначен для сведений о совместимости с серверами, позволяющими пользователям скрывать контакты |
| в определенных группах. |
| </td> |
| </tr> |
| <tr> |
| <td>«1» — контакты, представленные в этой группе, могут отображаться в интерфейсах пользователя приложений.</td> |
| </tr> |
| <tr> |
| <td rowspan="2">{@link android.provider.ContactsContract.Settings}</td> |
| <td rowspan="2"> |
| {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE}</td> |
| <td> |
| «0» — для этого аккаунта и аккаунтов этого типа контакты, не принадлежащие к группе, |
| не отображаются в интерфейсах пользователя приложений Android. |
| </td> |
| <td rowspan="2"> |
| По умолчанию контакты скрыты, если ни один из их необработанных контактов не принадлежит группе |
| (принадлежность необработанного контакта к группе указывается в одном или нескольких строках |
| {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} |
| в таблице {@link android.provider.ContactsContract.Data}). |
| Установив этот флаг в строке таблицы {@link android.provider.ContactsContract.Settings} |
| для типа аккаунта и имени аккаунта, вы можете принудительно сделать видимыми контакты, не принадлежащие какой-либо группе. |
| Один из вариантов использования этого флага — отображение контактов с серверов, на которых не используются группы. |
| </td> |
| </tr> |
| <tr> |
| <td> |
| «1» — для этого аккаунта и аккаунтов этого типа контакты, не принадлежащие к группе, |
| отображаются в интерфейсах пользователя приложений Android. |
| </td> |
| |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.SyncState}</td> |
| <td>(все)</td> |
| <td> |
| Эта таблица используется для хранения метаданных для вашего адаптера синхронизации. |
| </td> |
| <td> |
| С помощью этой таблицы вы можете на постоянной основе хранить на устройстве сведения о состоянии синхронизации и другие связанные с |
| синхронизацией данные. |
| </td> |
| </tr> |
| </table> |
| <h2 id="Access">Доступ к поставщику контактов</h2> |
| <p> |
| В этом разделе рассматриваются инструкции по получению доступа к данным из поставщика контактов, в частности, |
| следующие: |
| </p> |
| <ul> |
| <li> |
| запросы объектов; |
| </li> |
| <li> |
| пакетное изменение; |
| </li> |
| <li> |
| получение и изменение данных с помощью намерений; |
| </li> |
| <li> |
| целостность данных. |
| </li> |
| </ul> |
| <p> |
| Дополнительные сведения о внесении изменений с помощью адаптеров синхронизации представлены в разделе |
| <a href="#SyncAdapters">Адаптеры синхронизации поставщика контактов</a>. |
| </p> |
| <h3 id="Entities">Запрос объектов</h3> |
| <p> |
| Таблицы поставщика контактов имеют иерархическую структуру, поэтому зачастую полезно |
| извлекать строку и все связанные с ней ее дочерние строки. Например, для отображения |
| всей информации о пользователе вы, возможно, захотите извлечь все строки |
| {@link android.provider.ContactsContract.RawContacts} для одной строки |
| {@link android.provider.ContactsContract.Contacts} или все строки |
| {@link android.provider.ContactsContract.CommonDataKinds.Email} для одной строки |
| {@link android.provider.ContactsContract.RawContacts}. Чтобы упростить этот процесс, в поставщике контактов имеются |
| <strong>объекты</strong>, которые выступают в роли соединителей базы данных между |
| таблицами. |
| </p> |
| <p> |
| Объект представляет собой подобие таблицы, состоящей из выбранных столбцов родительской таблицы и ее дочерней таблицы. |
| При запросе объекта вы предоставляете проекцию и критерии поиска на основе доступных в |
| объекте столбцов. В результате вы получаете объект {@link android.database.Cursor}, в котором |
| содержится одна строка для каждой извлеченной строки дочерней таблицы. Например, если запросить объект |
| {@link android.provider.ContactsContract.Contacts.Entity} для имени контакта и все строки |
| {@link android.provider.ContactsContract.CommonDataKinds.Email} для всех необработанных контактов, |
| соответствующих этому имени, вы получите объект {@link android.database.Cursor}, содержащий по одной строке |
| для каждой строки {@link android.provider.ContactsContract.CommonDataKinds.Email}. |
| </p> |
| <p> |
| Использование объектов упрощает запросы. С помощью объекта можно извлечь сразу все данные для |
| контакта или необработанного контакта, вместо того, чтобы сначала делать запрос к родительской таблице для получения |
| идентификатора и последующего запроса к дочерней таблице с использованием полученного идентификатора. Кроме того, поставщик контактов обрабатывает запрос |
| объекта за одну транзакцию, что гарантирует внутреннюю согласованность полученных |
| данных. |
| </p> |
| <p class="note"> |
| <strong>Примечание.</strong> Объект обычно содержит не все столбцы |
| родительской и дочерней таблиц. Если вы попытаетесь изменить имя столбца, который отсутствует в списке |
| констант имени столбца для объекта, вы получите {@link java.lang.Exception}. |
| </p> |
| <p> |
| Ниже представлен пример кода для получения всех строк необработанного контакта для контакта. Это фрагмент |
| более крупного приложения, в котором имеются две операции: «основная» и «для получения сведений». Основная операция |
| служит для получения списка строк контактов; при выборе пользователем контакта операция отправляет его идентификатор в операцию |
| для получения сведений. Операция для получения сведений использует объект {@link android.provider.ContactsContract.Contacts.Entity} |
| для отображения всех строк данных, полученных ото всех необработанных контактов, которые связаны с выбранным |
| контактом. |
| </p> |
| <p> |
| Вот фрагмент кода операции «для получения сведений»: |
| </p> |
| <pre> |
| ... |
| /* |
| * 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. |
| } |
| </pre> |
| <p> |
| По завершении загрузки {@link android.app.LoaderManager} выполняет обратный вызов метода |
| {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D) |
| onLoadFinished()}. Одним их входящих аргументов для этого метода является |
| {@link android.database.Cursor} с результатом запроса. В своем приложении вы можете |
| получить данные из этого объекта {@link android.database.Cursor} для его отображения или дальнейшей работы с ним. |
| </p> |
| <h3 id="Transactions">Пакетное изменение</h3> |
| <p> |
| При каждой возможности данные в поставщике контактов следует вставлять, обновлять и удалять в |
| «пакетном режиме» путем создания {@link java.util.ArrayList} из объектов |
| {@link android.content.ContentProviderOperation} и вызова метода |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Поскольку |
| поставщик контактов выполняет все операции в методе |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} за одну |
| транзакцию, ваши изменения всегда будут находиться в рамках репозитория контактов и |
| всегда будут согласованными. Пакетное изменение также упрощает вставку необработанного контакта одновременно с его подробными |
| данными. |
| </p> |
| <p class="note"> |
| <strong>Примечание.</strong> Чтобы изменить <em>отдельный</em> необработанный контакт, рекомендуется отправить намерение в |
| приложение для работы с контактами на устройстве вместо обработки изменения в вашем приложении. |
| Более подробно эта операция описана в разделе |
| <a href="#Intents">Получение и изменение данных с помощью намерений</a>. |
| </p> |
| <h4>Пределы</h4> |
| <p> |
| Пакетное изменение большого количества операций может заблокировать выполнение других процессов, |
| что может негативно сказаться на работе пользователя с приложением. Чтобы упорядочить все необходимые изменения |
| в рамках как можно меньшего количества отдельных списков и при этом предотвратить |
| блокирование работы системы, следует задать <strong>пределы</strong> для одной или нескольких операций. |
| Предел представляет собой объект {@link android.content.ContentProviderOperation}, в качестве значения параметра |
| {@link android.content.ContentProviderOperation#isYieldAllowed()} которого задано |
| <code>true</code>. При достижении поставщиком контактов предела он приостанавливает свою работу, |
| чтобы могли выполняться другие процессы, и закрывает текущую транзакцию. Когда поставщик запускается снова, он |
| выполняет следующую операцию в {@link java.util.ArrayList} и запускает |
| новую транзакцию. |
| </p> |
| <p> |
| Использование пределов позволяет за один вызов метода |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} выполнять более одной транзакции. По этой причине |
| вам следует задать предел для последней операции с набором связанных строк. |
| Например, необходимо задать предел для последней операции в наборе, которая |
| добавляет строки необработанного контакта и связанные с ним строки данных, или для последней операции с набором строк, связанных |
| с одним контактом. |
| </p> |
| <p> |
| Пределы также являются единицами атомарных операций. Все операции доступа в промежутке между двумя пределами завершаются либо |
| успехом, либо сбоем в рамках одной единицы. Если любой из пределов не задан, наименьшей |
| атомарной операцией считается весь пакет операций. Использование пределов позволяет предотвратить |
| снижение производительности системы и одновременно обеспечить выполнение набора |
| операций на атомарном уровне. |
| </p> |
| <h4>Изменение обратных ссылок</h4> |
| <p> |
| При вставке новой строки необработанного контакта и связанных с ним рядов данных в виде набора объектов |
| {@link android.content.ContentProviderOperation} вам приходится связывать строки данных |
| со строкой необработанного контакта путем вставки значения |
| {@code android.provider.BaseColumns#_ID} необработанного контакта в виде значения |
| {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Однако это значение |
| недоступно, когда вы создаете{@link android.content.ContentProviderOperation} |
| для строки данных, поскольку вы еще не применили |
| {@link android.content.ContentProviderOperation} для строки необработанного контакта. Чтобы обойти это ограничение, |
| в классе {@link android.content.ContentProviderOperation.Builder} предусмотрен метод |
| {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}. |
| С помощью этого метода можно вставлять или изменять столбец |
| с результатом предыдущей операции. |
| </p> |
| <p> |
| В методе {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} |
| предусмотрено два аргумента: |
| </p> |
| <dl> |
| <dt> |
| <code>key</code> |
| </dt> |
| <dd> |
| Ключ для пары «ключ-значение». Значением этого аргумента должно быть имя столбца |
| в таблице, которую вы изменяете. |
| </dd> |
| <dt> |
| <code>previousResult</code> |
| </dt> |
| <dd> |
| Индекс значения, начинающийся с «0», в массиве объектов |
| {@link android.content.ContentProviderResult} из метода |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. По мере |
| выполнения пакетных операций результат каждой операции сохраняется в |
| промежуточном массиве результатов. Значением <code>previousResult</code> является индекс |
| одного из этих результатов, который извлекается и хранится со значением |
| <code>key</code>. Благодаря этому можно вставить новую запись необработанного контакта и получить обратно его значение |
| {@code android.provider.BaseColumns#_ID}, а затем создать «обратную ссылку» на |
| значение при добавлении строки {@link android.provider.ContactsContract.Data}. |
| <p> |
| Целиком весь результат создается при первом вызове метода |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. |
| Размер результата равен размеру {@link java.util.ArrayList} предоставленных вами объектов |
| {@link android.content.ContentProviderOperation}. Однако для всех |
| элементов в массиве результатов присваивается значение <code>null</code>, и при попытке |
| воспользоваться обратной ссылкой на результат еще не выполненной операции метод |
| {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} |
| выдает {@link java.lang.Exception}. |
| |
| </p> |
| </dd> |
| </dl> |
| <p> |
| Ниже представлены фрагменты кода для вставки нового необработанного контакта и его данных в пакетном режиме. Они включают |
| код, который задает предел и использует обратную ссылку. Эти фрагменты |
| представляют собой расширенную версию метода <code>createContacEntry()</code>, который входит в класс |
| <code>ContactAdder</code> в примере приложения |
| <code><a href="{@docRoot}resources/samples/ContactManager/index.html"> |
| Contact Manager</a></code>. |
| </p> |
| <p> |
| Первый фрагмент кода служит для извлечения данных контакта из пользовательского интерфейса. На этом этапе пользователь уже выбрал |
| аккаунт, для которого необходимо добавить новый необработанный контакт. |
| </p> |
| <pre> |
| // 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()); |
| </pre> |
| <p> |
| В следующем фрагменте кода создается операция для вставки строки необработанного контакта в таблицу |
| {@link android.provider.ContactsContract.RawContacts}: |
| </p> |
| <pre> |
| /* |
| * 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()); |
| </pre> |
| <p> |
| Затем код создает строки данных для строк отображаемого имени, телефона и адреса эл. почты. |
| </p> |
| <p> |
| Каждый объект компонента операции использует метод |
| {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} |
| для получения |
| {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Ссылка возвращается |
| обратно к объекту {@link android.content.ContentProviderResult} из первой операции, |
| в результате чего добавляется строка необработанного контакта и возвращается его новое значение |
| {@code android.provider.BaseColumns#_ID}. После этого каждая строка данных автоматически связывается по своему |
| {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} |
| с новой строкой {@link android.provider.ContactsContract.RawContacts}, которой она принадлежит. |
| </p> |
| <p> |
| Объект {@link android.content.ContentProviderOperation.Builder}, который добавляет строку адреса эл. почты, |
| помечается флагом с помощью метода {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean) |
| withYieldAllowed()}, который задает предел: |
| </p> |
| <pre> |
| // 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()); |
| </pre> |
| <p> |
| В последнем фрагменте кода представлен вызов метода |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} |
| для вставки нового необработанного контакта и его строк данных. |
| </p> |
| <pre> |
| // 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); |
| } |
| } |
| </pre> |
| <p> |
| С помощью пакетных операций можно также реализовать<strong>оптимистическое управление параллелизмом</strong>. |
| Это метод применения транзакций изменения без необходимости блокировать базовый репозиторий. |
| Чтобы воспользоваться этим методом, необходимо применить транзакцию и проверить наличие других изменений, |
| которые могли быть внесены в это же время. Если обнаружится, что имеется несогласованное изменение, |
| транзакцию можно откатить и выполнить повторно. |
| </p> |
| <p> |
| Оптимистическое управление параллелизмом подходит для мобильных устройств, где с системой одновременно взаимодействует только один пользователь, |
| а одновременный доступ к репозиторию данных нескольких пользователей — довольно редкое явление. Поскольку не применяется блокировка, |
| экономится ценное время, которое требуется на установку блокировок или ожидания того, когда другие транзакции отменят свои блокировки. |
| </p> |
| <p> |
| Ниже представлен порядок использования оптимистического управления параллелизмом при обновлении одной строки |
| {@link android.provider.ContactsContract.RawContacts}. |
| </p> |
| <ol> |
| <li> |
| Извлеките столбец {@link android.provider.ContactsContract.SyncColumns#VERSION} |
| необработанного контакта, а также другие данные, которые необходимо извлечь. |
| </li> |
| <li> |
| Создайте объект {@link android.content.ContentProviderOperation.Builder}, подходящий для |
| применения ограничения, с помощью метода |
| {@link android.content.ContentProviderOperation#newAssertQuery(Uri)}. Для URI контента |
| используйте {@link android.provider.ContactsContract.RawContacts#CONTENT_URI |
| RawContacts.CONTENT_URI}, |
| добавив к нему {@code android.provider.BaseColumns#_ID} необработанного контакта. |
| </li> |
| <li> |
| Для объекта {@link android.content.ContentProviderOperation.Builder} вызовите метод |
| {@link android.content.ContentProviderOperation.Builder#withValue(String, Object) |
| withValue()}, чтобы сравнить столбец {@link android.provider.ContactsContract.SyncColumns#VERSION} |
| с номером версии, которую вы только что получили. |
| </li> |
| <li> |
| Для того же объекта {@link android.content.ContentProviderOperation.Builder} вызовите метод |
| {@link android.content.ContentProviderOperation.Builder#withExpectedCount(int) |
| withExpectedCount()}, чтобы убедиться в том, что проверочное утверждение проверяет только одну строка. |
| </li> |
| <li> |
| Вызовите метод {@link android.content.ContentProviderOperation.Builder#build()}, чтобы создать объект |
| {@link android.content.ContentProviderOperation}, затем добавьте этот объект в качестве первого объекта в |
| {@link java.util.ArrayList}, который вы передаете в метод |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. |
| </li> |
| <li> |
| Примените пакетную транзакцию. |
| </li> |
| </ol> |
| <p> |
| Если в промежутке между считыванием строки и попыткой ее изменения строка необработанного контакта была обновлена другой |
| операцией, assert {@link android.content.ContentProviderOperation} |
| завершится сбоем и в выполнении всего пакета операций будет отказано. Можно выбрать повторное выполнение |
| пакета или выполнить другое действие. |
| </p> |
| <p> |
| В примере кода ниже демонстрируется, как создать assert |
| {@link android.content.ContentProviderOperation} после запроса одного необработанного контакта с помощью |
| {@link android.content.CursorLoader}. |
| </p> |
| <pre> |
| /* |
| * 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 |
| } |
| </pre> |
| <h3 id="Intents">Получение и изменение данных с помощью намерений</h3> |
| <p> |
| С помощью отправки намерения в приложение для работы с контактами, которое имеется на устройстве, можно в обход получить доступ |
| к поставщику контактов. Намерение запускает пользовательский интерфейс приложения на устройстве, посредством которого пользователь |
| может работать с контактами. Такой тип доступа позволяет пользователю выполнять следующие действия: |
| <ul> |
| <li>выбор контактов из списка и их возврат в приложение для дальнейшей работы;</li> |
| <li>изменение данных существующего контакта;</li> |
| <li>вставка нового необработанного контакта для любых других аккаунтов;</li> |
| <li>удаление контакта или его данных.</li> |
| </ul> |
| <p> |
| Если пользователь вставляет или обновляет данные , вы можете сначала собрать эти данные, а затем отправить их вместе |
| с намерением. |
| </p> |
| <p> |
| При использовании намерений для доступа к поставщику контактов посредством приложения для работы с контактами, имеющегося на устройстве, вам |
| не нужно создавать собственный пользовательский интерфейс или код для доступа к поставщику. Также вам |
| не нужно запрашивать разрешение на чтение или запись в поставщик. Приложение для работы с контактами, имеющееся на устройстве, может |
| делегировать вам разрешение на чтение контакта, и поскольку вы вносите изменения |
| в поставщик через другое приложение, вам не нужно разрешение на запись. |
| </p> |
| <p> |
| Более подробно общий процесс отправки намерения для получения доступа к поставщику описан в руководстве |
| <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Основные сведения о поставщике контента</a> |
| в разделе «Доступ к данным посредством намерений». В таблице 4 ниже представлены сводные сведения об операциях, |
| типе MIME и значениях данных, которые используются для доступных задач. Значения |
| дополнительных данных, которые можно использовать для |
| {@link android.content.Intent#putExtra(String, String) putExtra()}, указаны в справочной |
| документации по {@link android.provider.ContactsContract.Intents.Insert}. |
| </p> |
| <p class="table-caption" id="table4"> |
| <strong>Таблица 4.</strong> Намерения в поставщике контактов. |
| </p> |
| <table style="width:75%"> |
| <tr> |
| <th scope="col" style="width:10%">Задача</th> |
| <th scope="col" style="width:5%">Действие</th> |
| <th scope="col" style="width:10%">Данные</th> |
| <th scope="col" style="width:10%">Тип MIME</th> |
| <th scope="col" style="width:25%">Примечания</th> |
| </tr> |
| <tr> |
| <td><strong>Выбор контакта из списка</strong></td> |
| <td>{@link android.content.Intent#ACTION_PICK}</td> |
| <td> |
| Одно из следующего: |
| <ul> |
| <li> |
| {@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI} |
| (отображение списка контактов); |
| </li> |
| <li> |
| {@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI} |
| (отображение номеров телефонов для необработанного контакта); |
| </li> |
| <li> |
| {@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal#CONTENT_URI |
| StructuredPostal.CONTENT_URI} |
| (отображение списка почтовых адресов для необработанного контакта); |
| </li> |
| <li> |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI} |
| (отображение адресов эл. почты для необработанного контакта). |
| </li> |
| </ul> |
| </td> |
| <td> |
| Не используется |
| </td> |
| <td> |
| Отображение списка необработанных контактов или списка данных необработанного контакта (в зависимости от |
| предоставленного URI контента). |
| <p> |
| Вызовите метод |
| {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()}, |
| который возвращает URI контента для выбранной строки. URI представлен в форме |
| URI контента таблицы, к которому добавлен <code>LOOKUP_ID</code> строки. |
| Приложение для работы с контактами, установленное на устройстве, делегирует этому URI контента |
| разрешения на чтение и запись, которые действуют в течение всего жизненного цикла вашей операции. Дополнительные сведения представлены в статье |
| <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Основные |
| сведения о поставщике контента</a>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><strong>Вставка нового необработанного контакта</strong></td> |
| <td>{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION}</td> |
| <td>Н/Д</td> |
| <td> |
| {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE |
| RawContacts.CONTENT_TYPE}, тип MIME для набора необработанных контактов. |
| </td> |
| <td> |
| Отображение экрана <strong>Добавить контакт</strong> в приложении для работы с контактами, которое установлено на устройстве. Отображаются |
| значения дополнительных данных, добавленных вами в намерение. При отправке с помощью метода |
| {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()} |
| URI контента нового добавленного необработанного контакта передается обратно в метод обратного вызова |
| {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()} |
| вашей операции в аргументе {@link android.content.Intent} в поле |
| data. Чтобы получить значение, вызовите метод {@link android.content.Intent#getData()}. |
| </td> |
| </tr> |
| <tr> |
| <td><strong>Изменение контакта</strong></td> |
| <td>{@link android.content.Intent#ACTION_EDIT}</td> |
| <td> |
| {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} |
| контакта. Операция редактора разрешит пользователю изменить любые данные, связанные с |
| этим контактом. |
| </td> |
| <td> |
| {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE |
| Contacts.CONTENT_ITEM_TYPE}, один контакт.</td> |
| <td> |
| Отображение экрана редактирования контакта в приложении для работы с контактами. Отображаются |
| значения дополнительных данных, добавленных вами в намерение. Когда пользователь нажимает на кнопку <strong>Готово</strong> для сохранения |
| внесенных изменений, ваша операция возвращается на передний план. |
| </td> |
| </tr> |
| <tr> |
| <td><strong>Отображение средства выбора, в котором также можно добавлять данные</strong></td> |
| <td>{@link android.content.Intent#ACTION_INSERT_OR_EDIT}</td> |
| <td> |
| Н/Д |
| </td> |
| <td> |
| {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE} |
| </td> |
| <td> |
| Это намерение также отображает экран средства выбора приложения для работы с контактами. Пользователь |
| может выбрать контакт для изменения или добавить новый контакт. В зависимости от выбора отображается экран редактирования или добавления контакта, |
| и отображаются дополнительные данные, |
| переданные вами в намерение. Если ваше приложение отображает такие данные контакта, как адрес эл. почты или номер телефона, |
| воспользуйтесь этим намерением, чтобы разрешить пользователю добавлять данные к существующему |
| контакту. |
| <p class="note"> |
| <strong>Примечание.</strong> Вам не нужно отправлять значение имени в дополнительные данные этого намерения, |
| поскольку пользователь всегда выбирает существующее имя или добавляет новое. Кроме того, |
| если отправить имя, а пользователь решит внести изменения, приложение для работы с контактами |
| отобразит отправленное вами имя, перезаписав предыдущее значение. Если пользователь |
| не заметит этого и сохранит изменения, старое значение будет утеряно. |
| </p> |
| </td> |
| </tr> |
| </table> |
| <p> |
| Приложение для работы с контактами, имеющееся на устройстве, не разрешает вам удалять необработанные контакты или любые его данные с |
| помощью намерений. Вместо этого для обработки необработанного контакта используйте метод |
| {@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()} |
| или {@link android.content.ContentProviderOperation#newDelete(Uri) |
| ContentProviderOperation.newDelete()}. |
| </p> |
| <p> |
| Ниже представлен фрагмент кода для создания и отправки намерения, который вставляет новый |
| необработанный контакт и его данные. |
| </p> |
| <pre> |
| // 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); |
| </pre> |
| <h3 id="DataIntegrity">Целостность данных</h3> |
| <p> |
| Поскольку в репозитории контактов содержится важная и конфиденциальная информация, которая, как ожидает пользователь, верна и |
| актуальна, в поставщике контактов предусмотрены четко определенные правила для обеспечения целостности данных. При изменении данных контактов вы обязаны |
| соблюдать эти правила. Вот наиболее |
| важные из этих правил: |
| </p> |
| <dl> |
| <dt> |
| Всегда добавляйте строку {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} |
| к каждой добавляемой вами строке {@link android.provider.ContactsContract.RawContacts}. |
| </dt> |
| <dd> |
| Если в таблице {@link android.provider.ContactsContract.Data} имеется строка {@link android.provider.ContactsContract.RawContacts} |
| без строки {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}, |
| то могут возникнуть |
| проблемы во время агрегирования. |
| </dd> |
| <dt> |
| Всегда связывайте новые строки {@link android.provider.ContactsContract.Data} с их |
| родительскими строками {@link android.provider.ContactsContract.RawContacts}. |
| </dt> |
| <dd> |
| Строка {@link android.provider.ContactsContract.Data}, которая не связана |
| с {@link android.provider.ContactsContract.RawContacts}, не будет отображаться в |
| приложении для работы с контактами, имеющемся на устройстве, а также может привести к проблемам с адаптерами синхронизации. |
| </dd> |
| <dt> |
| Следует изменять данные только тех необработанных контактов, которыми вы владеете. |
| </dt> |
| <dd> |
| Помните о том, что поставщик контактов обычно управляет данными из |
| нескольких аккаунтов различных типов или служб в Интернете. Необходимо убедиться в том, что ваше приложение изменяет |
| или удаляет данные только для тех строк, которые принадлежат вам, а также в том, что оно вставляет данные с использованием только тех типов и имени аккаунта, |
| которыми вы управляете. |
| </dd> |
| <dt> |
| Всегда используйте |
| для центров, URI контента, путей URI, имен столбцов, типов MIME и значений |
| {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE} только те константы, которые определены в классе {@link android.provider.ContactsContract} и его подклассах. |
| </dt> |
| <dd> |
| Это позволит избежать ошибок. Если какая либо константа устарела, компилятор сообщит об этом |
| с помощью соответствующего предупреждения. |
| </dd> |
| </dl> |
| <h3 id="CustomData">Настраиваемые строки данных</h3> |
| <p> |
| Создав и используя собственные типы MIME, вы можете вставлять, изменять, удалять и извлекать |
| в таблице{@link android.provider.ContactsContract.Data} собственные строки данных. Ваши строки |
| ограничены использованием столбца, который определен в |
| {@link android.provider.ContactsContract.DataColumns}, однако вы можете сопоставить ваши собственные имена столбцов по типам строк |
| с именами столбцов по умолчанию. Данные для ваших строк отображаются в приложении для работы с контактами, которое имеется на устройстве, |
| однако их не удастся изменить или удалить, а также пользователи не смогут |
| добавить дополнительные данные. Чтобы разрешить пользователям изменять ваши настраиваемые строки данных, необходимо реализовать в вашем приложении операцию |
| редактора. |
| </p> |
| <p> |
| Для отображения настраиваемых данных укажите файл <code>contacts.xml</code>, содержащий элемент |
| <code><ContactsAccountType></code> и один или несколько его |
| <code><ContactsDataKind></code> дочерних элементов. Дополнительные сведения об этом представлены в разделе |
| <a href="#SocialStreamDataKind"><code><ContactsDataKind> element</code></a>. |
| </p> |
| <p> |
| Дополнительные сведения о настраиваемых типах MIME представлены в руководстве |
| <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">Создание |
| поставщика контента</a>. |
| </p> |
| <h2 id="SyncAdapters">Адаптеры синхронизации поставщика контактов</h2> |
| <p> |
| Поставщик контактов разработан специально для обработки операций <strong>синхронизации</strong> |
| данных контактов между устройством и службой в Интернете. Благодаря этому пользователи |
| могут загружать существующие данные на новое устройство и отправлять их в новый аккаунт. |
| Синхронизация также обеспечивает предоставление пользователю всегда актуальных сведений, независимо от |
| источника их добавления и внесенных в них изменений. Еще одно преимущество синхронизации заключается в том, |
| что данные контактов доступны даже в том случае, если устройство не подключено к сети. |
| </p> |
| <p> |
| Несмотря на множество различных способов реализации синхронизации данных, в системе Android имеется |
| подключаемая платформа синхронизации, которая позволяет автоматизировать выполнение следующих задач: |
| <ul> |
| |
| <li> |
| проверка доступности сети; |
| </li> |
| <li> |
| планирование и выполнение синхронизации на основе предпочтений пользователя; |
| </li> |
| <li> |
| перезапуск остановленных процессов синхронизации. |
| </li> |
| </ul> |
| <p> |
| Для использования этой платформы вы предоставляете подключаемый модуль адаптера синхронизации. Каждый адаптер синхронизации является уникальным |
| для службы и поставщика контента, однако способен работать с несколькими аккаунтами в одной службе. В платформе |
| также предусмотрена возможность использовать несколько адаптеров синхронизации для одной и той же службы или поставщика. |
| </p> |
| <h3 id="SyncClassesFiles">Классы и файлы адаптера синхронизации</h3> |
| <p> |
| Адаптер синхронизации реализуется как подкласс класса |
| {@link android.content.AbstractThreadedSyncAdapter} и устанавливается в составе приложения |
| Android. Система узнает о наличии адаптера синхронизации из элементов в манифесте |
| вашего приложения, а также из особого файла XML, на который имеется указание в манифесте. В файле XML определяются |
| тип аккаунта в онлайн-службе и центр поставщика контента, которые вместе служат уникальными |
| идентификаторами адаптера. Адаптер синхронизации находится в неактивном состоянии до тех пор, пока пользователь не добавит |
| тип аккаунта и не включит синхронизацию |
| с поставщиком контента. На этом этапе система вступает в управление адаптером |
| , при необходимости вызывая его для синхронизации данных между поставщиком контента и сервером. |
| </p> |
| <p class="note"> |
| <strong>Примечание.</strong> Использование типа аккаунта для идентификации адаптера синхронизации |
| позволяет системе обнаруживать и группировать адаптеры синхронизации, которые обращаются к разным службам |
| из одной и той же организации. Например, у всех адаптеров синхронизации для онлайн-служб Google |
| один и тот же тип аккаунта — <code>com.google</code>. Когда пользователи добавляют на свои устройства аккаунт Google, все |
| установленные адаптеры синхронизации группируются вместе; каждый из адаптеров |
| синхронизируется только с отдельным поставщиком контента на устройстве. |
| </p> |
| <p> |
| Поскольку в большинстве служб пользователям сначала необходимо подтвердить свою подлинность, прежде чем они смогут получить доступ к данным, |
| система Android предлагает платформу аутентификации, которая аналогична |
| платформе адаптера синхронизации и зачастую используется совместно с ней. Платформа аутентификации |
| использует подключаемые структуры проверки подлинности, которые представляют собой подклассы класса |
| {@link android.accounts.AbstractAccountAuthenticator}. Такая структура проверяет |
| подлинность пользователя следующим образом: |
| <ol> |
| <li> |
| Сначала собираются сведения об имени пользователя и его пароле или аналогичная информация (<strong>учетные данные</strong> |
| пользователя). |
| </li> |
| <li> |
| Затем учетные данные оправляются в службу. |
| </li> |
| <li> |
| Наконец, изучается ответ, полученный от службы. |
| </li> |
| </ol> |
| <p> |
| Если служба приняла учетные данные, структура проверки подлинности может |
| сохранить их для использования в дальнейшем. Благодаря использованию структур проверки подлинности |
| {@link android.accounts.AccountManager} может предоставить доступ к любым маркерам аутентификации, которые |
| поддерживает структура проверки подлинности и которые она решает предоставить, например, к маркерам аутентификации OAuth2. |
| </p> |
| <p> |
| Несмотря на то что аутентификация не требуется, она используется большинством служб для работы с контактами. |
| Тем не менее, вам не обязательно использовать платформу аутентификации Android для проверки подлинности. |
| </p> |
| <h3 id="SyncAdapterImplementing">Реализация адаптера синхронизации</h3> |
| <p> |
| Чтобы реализовать адаптер синхронизации для поставщика контактов, начните с создания |
| приложения Android, которое содержит следующие компоненты. |
| </p> |
| <dl> |
| <dt> |
| Компонент {@link android.app.Service}, который отвечает на запросы системы |
| для привязки к адаптеру синхронизации. |
| </dt> |
| <dd> |
| Когда системе требуется запустить синхронизацию, она вызывает метод |
| {@link android.app.Service#onBind(Intent) onBind()} службы, чтобы получить объект |
| {@link android.os.IBinder} для адаптера синхронизации. Благодаря этому система |
| может вызывать методы адаптера между процессами. |
| <p> |
| В |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">примере адаптера синхронизации</a> именем класса этой службы является |
| <code>com.example.android.samplesync.syncadapter.SyncService</code>. |
| </p> |
| </dd> |
| <dt> |
| Адаптер синхронизации, фактически реализованный как конкретный подкласс |
| класса {@link android.content.AbstractThreadedSyncAdapter}. |
| </dt> |
| <dd> |
| Этот класс не подходит для загрузки данных с сервера, отправки данных |
| с устройства и разрешения конфликтов. Основную свою работу адаптер |
| выполняет в методе {@link android.content.AbstractThreadedSyncAdapter#onPerformSync( |
| Account, Bundle, String, ContentProviderClient, SyncResult) |
| onPerformSync()}. Этот класс допускает создание только одного экземпляра. |
| <p> |
| В |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">примере адаптера синхронизации</a> адаптер определяется в классе |
| <code>com.example.android.samplesync.syncadapter.SyncAdapter</code>. |
| </p> |
| </dd> |
| <dt> |
| Подкласс класса {@link android.app.Application}. |
| </dt> |
| <dd> |
| Этот класс выступает в роли фабрики для единственного экземпляра адаптера синхронизации. Воспользуйтесь методом |
| {@link android.app.Application#onCreate()}, чтобы создать экземпляр адаптера синхронизации, а затем |
| предоставьте статический метод get, чтобы возвратить единственный экземпляр в метод |
| {@link android.app.Service#onBind(Intent) onBind()} службы |
| адаптера синхронизации. |
| </dd> |
| <dt> |
| <strong>Необязательно:</strong> компонент {@link android.app.Service}, который отвечает на запросы |
| системы для аутентификации пользователей. |
| </dt> |
| <dd> |
| {@link android.accounts.AccountManager} запускает службу, чтобы начать процесс |
| аутентификации. Метод {@link android.app.Service#onCreate()} службы создает экземпляр |
| объекта структуры проверки подлинности. Когда системе требуется запустить аутентификацию аккаунта пользователя для |
| адаптера синхронизации приложения, она вызывает метод |
| {@link android.app.Service#onBind(Intent) onBind()} службы, чтобы получить объект |
| {@link android.os.IBinder} для структуры проверки подлинности. Благодаря этому система |
| может вызывать методы структуры проверки подлинности между процессами. |
| <p> |
| В |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">примере адаптера синхронизации</a> именем класса этой службы является |
| <code>com.example.android.samplesync.authenticator.AuthenticationService</code>. |
| </p> |
| </dd> |
| <dt> |
| <strong>Необязательно:</strong> конкретный подкласс класса |
| {@link android.accounts.AbstractAccountAuthenticator}, который обрабатывает запросы на |
| аутентификацию. |
| </dt> |
| <dd> |
| В этом классе имеются методы, которые {@link android.accounts.AccountManager} вызывает |
| для проверки подлинности учетных данных пользователя на сервере. Подробности процесса |
| аутентификации значительно различаются в зависимости от технологии, используемой на сервере. Чтобы узнать подробнее об аутентификации, |
| обратитесь к соответствующей документации к программному обеспечению используемого сервера. |
| <p> |
| В |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">примере адаптера синхронизации</a> структура проверки подлинности определяется в классе |
| <code>com.example.android.samplesync.authenticator.Authenticator</code>. |
| </p> |
| </dd> |
| <dt> |
| Файлы XML, в которых определяются адаптер синхронизация и структура проверки подлинности для системы. |
| </dt> |
| <dd> |
| Описанные ранее компоненты службы адаптера синхронизации и структуры проверки подлинности определяются |
| в элементах |
| <code><<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>></code> |
| в манифесте приложения. Эти элементы |
| включают дочерние элементы |
| <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> |
| , в которых имеются определенные данные для |
| системы. |
| <ul> |
| <li> |
| Элемент |
| <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> |
| для службы адаптера синхронизации указывает на файл |
| XML <code>res/xml/syncadapter.xml</code>. В свою очередь, в этом файле задается |
| URI веб-службы для синхронизации с поставщиком контактов, |
| а также тип аккаунта для этой веб-службы. |
| </li> |
| <li> |
| <strong>Необязательно:</strong> элемент |
| <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> |
| для структуры проверки подлинности указывает на файл XML |
| <code>res/xml/authenticator.xml</code>. В свою очередь, в этом файле задается |
| тип аккаунта, который поддерживает структура проверки подлинности, а также ресурсы пользовательского интерфейса, |
| которые отображаются в процессе аутентификации. Тип аккаунта, указанный в этом |
| элементе, должен совпадать с типом аккаунта, который задан для |
| адаптера синхронизации. |
| </li> |
| </ul> |
| </dd> |
| </dl> |
| <h2 id="SocialStream">Потоки данных из социальных сетей</h2> |
| <p> |
| Для управления входящими данными из социальных сетей используются таблицы {@code android.provider.ContactsContract.StreamItems} |
| и |
| {@code android.provider.ContactsContract.StreamItemPhotos}. Можно создать адаптер синхронизации, который добавляет поток данных |
| из вашей собственной сети в эти таблицы, либо вы можете считывать поток данных из этих таблиц и отображать |
| их в собственном приложении. Можно также реализовать оба этих способа. С помощью этих функций вы можете интегрировать службы социальных сетей |
| в компоненты Android для работы с социальными сетями. |
| </p> |
| <h3 id="StreamText">Текст из потока данных из социальных сетей</h3> |
| <p> |
| Элементы потока всегда ассоциируются с необработанным контактом. Идентификатор |
| {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} связывается со значением |
| <code>_ID</code> необработанного контакта. Тип аккаунта и его имя для необработанного |
| контакта также хранятся в строке элемента потока. |
| </p> |
| <p> |
| Данные из потока следует хранить в следующих столбцах: |
| </p> |
| <dl> |
| <dt> |
| {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE} |
| </dt> |
| <dd> |
| <strong>Обязательный.</strong> Тип аккаунта пользователя для необработанного контакта, связанного с |
| этим элементом потока. Не забудьте задать это значение при вставке элемента потока. |
| </dd> |
| <dt> |
| {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME} |
| </dt> |
| <dd> |
| <strong>Обязательный.</strong> Имя аккаунта пользователя для необработанного контакта, связанного с |
| этим элементом потока. Не забудьте задать это значение при вставке элемента потока. |
| </dd> |
| <dt> |
| Столбцы идентификатора |
| </dt> |
| <dd> |
| <strong>Обязательный.</strong> При вставке элемента потока необходимо вставить |
| указанные ниже столбцы идентификатора. |
| <ul> |
| <li> |
| {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}: значение |
| {@code android.provider.BaseColumns#_ID} для контакта, с которым ассоциирован |
| этот элемент потока. |
| </li> |
| <li> |
| {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}: значение |
| {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} для контакта, с которым ассоциирован |
| этот элемент потока. |
| </li> |
| <li> |
| {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}: значение |
| {@code android.provider.BaseColumns#_ID} для необработанного контакта, с которым ассоциирован |
| этот элемент потока. |
| </li> |
| </ul> |
| </dd> |
| <dt> |
| {@code android.provider.ContactsContract.StreamItemsColumns#COMMENTS} |
| </dt> |
| <dd> |
| Необязательный. В нем хранится сводная информация, которую можно отобразить в начале элемента потока. |
| </dd> |
| <dt> |
| {@code android.provider.ContactsContract.StreamItemsColumns#TEXT} |
| </dt> |
| <dd> |
| Текст элемента потока: либо контент, опубликованный источником элемента, |
| либо описание некоторого действия, сгенерировавшего элемент потока. В этом столбце могут содержаться |
| любое форматирование и встроенные изображения ресурсов, рендеринг которых можно выполнить с помощью метода |
| {@link android.text.Html#fromHtml(String) fromHtml()}. Поставщик может обрезать слишком длинный контент |
| или заменить его часть многоточием, однако он попытается избежать нарушения тегов. |
| </dd> |
| <dt> |
| {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} |
| </dt> |
| <dd> |
| Текстовая строка с информацией о времени вставки или обновления элемента в |
| <em>миллисекундах</em> от начала отсчета времени. Обслуживанием этого столбца занимаются приложения, которые вставляют или |
| обновляют элементы потока; поставщик контактов не выполняет |
| это автоматически. |
| </dd> |
| </dl> |
| <p> |
| Для отображения идентификационной информации для элементов потока воспользуйтесь |
| {@code android.provider.ContactsContract.StreamItemsColumns#RES_ICON}, |
| {@code android.provider.ContactsContract.StreamItemsColumns#RES_LABEL} и |
| {@code android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} для связывания с ресурсами |
| в вашем приложении. |
| </p> |
| <p> |
| В таблице {@code android.provider.ContactsContract.StreamItems} также имеются столбцы |
| {@code android.provider.ContactsContract.StreamItemsColumns#SYNC1}—{@code android.provider.ContactsContract.StreamItemsColumns#SYNC4}, |
| которые предназначены исключительно для |
| адаптеров синхронизации. |
| </p> |
| <h3 id="StreamPhotos">Фотографии из потока данных из социальных сетей</h3> |
| <p> |
| Фотографии, связанные с элементом потока, хранятся в таблице |
| {@code android.provider.ContactsContract.StreamItemPhotos}. Столбец |
| {@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID} |
| в этой таблице связан со столбцом {@code android.provider.BaseColumns#_ID} |
| в таблице {@code android.provider.ContactsContract.StreamItems}. Ссылки на фотографии хранятся в следующих столбцах |
| таблицы: |
| </p> |
| <dl> |
| <dt> |
| Столбец {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} (объект BLOB). |
| </dt> |
| <dd> |
| Представление фотографии в двоичном формате и с измененным поставщиком размером для ее хранения и отображения. |
| Этот столбец доступен для обеспечения обратной совместимости с предыдущими версиями поставщика |
| контактов, которые использовались для хранения фотографий. Однако в текущей версии |
| поставщика мы не рекомендуем использовать этот столбец для хранения фотографий. Вместо этого воспользуйтесь столбцом |
| {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} или |
| {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} (или обоими |
| столбцами, как описано далее) для хранения фотографий в файле. В этом |
| столбце теперь хранятся миниатюры фотографий, доступных для чтения. |
| </dd> |
| <dt> |
| {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} |
| </dt> |
| <dd> |
| Числовой идентификатор фотографии для необработанного контакта. Добавьте это значение к константе |
| {@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI}, |
| чтобы получить URI контента для одного файла фотографии, а затем вызовите метод |
| {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) |
| openAssetFileDescriptor()}, чтобы получить средство обработки файла фотографии. |
| </dd> |
| <dt> |
| {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} |
| </dt> |
| <dd> |
| URI контента, указывающий на файл фотографии, для фотографии, которая представлена этой строкой. |
| Вызовите метод {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) |
| openAssetFileDescriptor()}, передав в него этот URI, чтобы получить средство обработки файла фотографии. |
| </dd> |
| </dl> |
| <h3 id="SocialStreamTables">Использование таблиц из потока данных из социальных сетей</h3> |
| <p> |
| Эти таблицы работают аналогично другим основным таблицам в поставщике контактов, за исключением указанных ниже моментов. |
| </p> |
| <ul> |
| <li> |
| Для работы с этими таблицами требуются дополнительные разрешения на доступ. Для чтения данных из них вашему приложению |
| должно быть предоставлено разрешение {@code android.Manifest.permission#READ_SOCIAL_STREAM}. Для |
| изменения таблиц ваше приложение должно иметь разрешение |
| {@code android.Manifest.permission#WRITE_SOCIAL_STREAM}. |
| </li> |
| <li> |
| Для таблицы {@code android.provider.ContactsContract.StreamItems} существует ограничение на количество строк, |
| которое можно хранить для каждого необработанного контакта. При достижении этого ограничения |
| поставщик контактов освобождает место для новых строк элементов потока путем автоматического удаления |
| строк со самой старой меткой |
| {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP}. Чтобы получить это ограничение, |
| запросите URI контента |
| {@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI}. Для всех аргументов, |
| отличных от URI контента, можно оставить значение <code>null</code>. Запрос возвращает |
| объект Cursor, в котором содержится одна строка с одним столбцом |
| {@code android.provider.ContactsContract.StreamItems#MAX_ITEMS}. |
| </li> |
| </ul> |
| |
| <p> |
| Класс {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} определяет |
| дочернюю таблицу объектов {@code android.provider.ContactsContract.StreamItemPhotos}, в которой содержатся |
| строки для одного элемента потока. |
| </p> |
| <h3 id="SocialStreamInteraction">Взаимодействие с потоками данных из социальных сетей</h3> |
| <p> |
| Управление потоком данных из социальных сетей осуществляется поставщиком контактов совместно с приложением для управления контактами, имеющимся на устройстве. |
| Такой подход позволяет организовать эффективное использование данных из социальных сетей |
| с данными о существующих контактах. Доступны указанные ниже функции. |
| </p> |
| <ul> |
| <li> |
| Организовав синхронизацию данных из социальной службы с поставщиком контактов посредством |
| адаптера синхронизации, вы можете получать данные о недавней активности контактов пользователя и хранить такие данные в таблицах |
| ,{@code android.provider.ContactsContract.StreamItems} |
| и {@code android.provider.ContactsContract.StreamItemPhotos} для использования в дальнейшем. |
| </li> |
| <li> |
| Помимо регулярной синхронизации, адаптер синхронизации можно настроить на получение |
| дополнительных данных при выборе пользователем контакта для просмотра. Благодаря этому ваш адаптер синхронизации |
| может получать фотографии высокого разрешения и самые актуальные элементы потока для контакта. |
| </li> |
| <li> |
| Регистрируя уведомление в приложении для работы с контактами и в поставщике |
| контактов, вы можете<em>получать</em> намерения при просмотре контакта и обновлять на этом этапе |
| данные о состоянии контакта из вашей службы. Такой подход может обеспечить большее быстродействие и меньший объем |
| использования полосы пропускания, чем выполнение полной синхронизации с помощью адаптера синхронизации. |
| </li> |
| <li> |
| Пользователи могут добавить контакт в вашу службу социальной сети, обратившись к контакту |
| в приложении для работы с контактами, которое имеется на устройстве. Это реализуется с помощью функции «пригласить контакт», |
| для включения которой используется сочетание операции, |
| которая добавляет существующий контакт в вашу сеть, и файла XML, в котором представлены сведения о вашем приложении для поставщика контактов и приложения для работы с |
| контактами. |
| </li> |
| </ul> |
| <p> |
| Регулярная синхронизация элементов потока с помощью поставщика контактов выполняется так же, |
| как и любая другая синхронизация. Дополнительные сведения о синхронизации представлены в разделе |
| <a href="#SyncAdapters">Адаптеры синхронизации поставщика контактов</a>. Регистрация уведомлений |
| и приглашение контактов рассматриваются в следующих двух разделах. |
| </p> |
| <h4>Регистрация для обработки просмотров контактов в социальных сетях</h4> |
| <p> |
| Чтобы зарегистрировать адаптер синхронизации для получения уведомлений о просмотрах пользователями контакта, |
| управление которым осуществляется вашим адаптером синхронизации, выполните указанные ниже действия. |
| </p> |
| <ol> |
| <li> |
| В каталоге <code>res/xml/</code> своего проекта создайте файл |
| <code>contacts.xml</code>. Если у вас уже есть этот файл, переходите к следующему действию. |
| </li> |
| <li> |
| В этом файле добавьте элемент |
| <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code>. |
| Если этот элемент уже существует, можете переходить к следующему действию. |
| </li> |
| <li> |
| Чтобы зарегистрировать службу, которой отправляется уведомление при открытии пользователем страницы со сведениями о контакте |
| в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут |
| <code>viewContactNotifyService="<em>serviceclass</em>"</code> к элементу, где |
| <code><em>serviceclass</em></code> — это полное имя класса службы, |
| которая должна получить намерение из приложения для работы с контактами. Для службы-уведомителя |
| используйте класс, который является расширением класса {@link android.app.IntentService}, чтобы разрешить службе |
| получать намерения. Данные во входящем намерении содержат URI контента необработанного |
| контакта, выбранного пользователем. В службе-уведомителе можно привязать адаптер синхронизации, а затем вызвать его |
| для обновления данных для необработанного контакта. |
| </li> |
| </ol> |
| <p> |
| Чтобы зарегистрировать операцию, которую следует вызвать при выборе пользователем элемента потока или фотографии (или обоих элементов), выполните указанные ниже действия. |
| </p> |
| <ol> |
| <li> |
| В каталоге <code>res/xml/</code> своего проекта создайте файл |
| <code>contacts.xml</code>. Если у вас уже есть этот файл, переходите к следующему действию. |
| </li> |
| <li> |
| В этом файле добавьте элемент |
| <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code>. |
| Если этот элемент уже существует, можете переходить к следующему действию. |
| </li> |
| <li> |
| Чтобы зарегистрировать одну из ваших операций для обработки выбора пользователем элемента потока |
| в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут |
| <code>viewStreamItemActivity="<em>activityclass</em>"</code> к элементу, где |
| <code><em>activityclass</em></code> — это полное имя класса операции, |
| которая должна получить намерение из приложения для работы с контактами. |
| </li> |
| <li> |
| Чтобы зарегистрировать одну из ваших операций для обработки выбора пользователем фотографии в потоке |
| в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут |
| <code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> к элементу, где |
| <code><em>activityclass</em></code> — это полное имя класса операции, |
| которая должна получить намерение из приложения для работы с контактами. |
| </li> |
| </ol> |
| <p> |
| Дополнительные сведения об элементе <code><ContactsAccountType></code> представлены в разделе |
| <a href="#SocialStreamAcctType">элемент <ContactsAccountType></a>. |
| </p> |
| <p> |
| Данные во входящем намерении содержат URI контента элемента или фотографии, выбранных пользователем. |
| Чтобы использовать разные операции для текстовых элементов и фотографий, используйте оба атрибута в одном файле. |
| </p> |
| <h4>Взаимодействие со службой социальной сети</h4> |
| <p> |
| Пользователям не обязательно выходить из приложения для работы с контактами, которое имеется на устройстве, чтобы пригласить контакт на сайт |
| социальной сети. Вместо этого приложение для работы с контактами может отправить намерение для приглашения |
| контакта в одну из ваших операций. Для этого выполните указанные ниже действия. |
| </p> |
| <ol> |
| <li> |
| В каталоге <code>res/xml/</code> своего проекта создайте файл |
| <code>contacts.xml</code>. Если у вас уже есть этот файл, переходите к следующему действию. |
| </li> |
| <li> |
| В этом файле добавьте элемент |
| <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code>. |
| Если этот элемент уже существует, можете переходить к следующему действию. |
| </li> |
| <li> |
| Добавьте следующие атрибуты: |
| <ul> |
| <li><code>inviteContactActivity="<em>activityclass</em>"</code>;</li> |
| <li> |
| <code>inviteContactActionLabel="@string/<em>invite_action_label</em>"</code>. |
| </li> |
| </ul> |
| Значение <code><em>activityclass</em></code> представляет собой полное имя класса операции, |
| которая должна получить намерение. Значение<code><em>invite_action_label</em></code> |
| — это текстовая строка, которая отображается в меню <strong>Добавить подключение</strong> |
| в приложении для работы с контактами. |
| </li> |
| </ol> |
| <p class="note"> |
| <strong>Примечание.</strong> <code>ContactsSource</code> — это устаревшее имя тега для |
| <code>ContactsAccountType</code>, которое больше не используется. |
| </p> |
| <h3 id="ContactsFile">Ссылка contacts.xml</h3> |
| <p> |
| В файле <code>contacts.xml</code> содержатся элементы XML, которые управляют взаимодействием вашего |
| адаптера синхронизации и вашего приложения с поставщиком контактов и приложением для работы с контактами. Эти |
| элементы описаны в следующих разделах. |
| </p> |
| <h4 id="SocialStreamAcctType">Элемент <ContactsAccountType></h4> |
| <p> |
| Элемент <code><ContactsAccountType></code> управляет взаимодействием вашего |
| приложения с приложением для работы с контактами. Ниже представлен его синтаксис. |
| </p> |
| <pre> |
| <ContactsAccountType |
| xmlns:android="http://schemas.android.com/apk/res/android" |
| inviteContactActivity="<em>activity_name</em>" |
| inviteContactActionLabel="<em>invite_command_text</em>" |
| viewContactNotifyService="<em>view_notify_service</em>" |
| viewGroupActivity="<em>group_view_activity</em>" |
| viewGroupActionLabel="<em>group_action_text</em>" |
| viewStreamItemActivity="<em>viewstream_activity_name</em>" |
| viewStreamItemPhotoActivity="<em>viewphotostream_activity_name</em>"> |
| </pre> |
| <p> |
| <strong>находится в:</strong> |
| </p> |
| <p> |
| <code>res/xml/contacts.xml</code> |
| </p> |
| <p> |
| <strong>может содержать:</strong> |
| </p> |
| <p> |
| <strong><code><ContactsDataKind></code></strong> |
| </p> |
| <p> |
| <strong>Описание</strong> |
| </p> |
| <p> |
| Этот элемент объявляет компоненты и элементы пользовательского интерфейса, с помощью которых пользователи могут приглашать свои контакты |
| в социальную сеть, уведомлять пользователей при обновлении одного из их потоков данных из социальных сетей и |
| др. |
| </p> |
| <p> |
| Обратите внимание, что префикс атрибута <code>android:</code> необязательно использовать для атрибутов |
| <code><ContactsAccountType></code>. |
| </p> |
| <p> |
| <strong>Атрибуты</strong> |
| </p> |
| <dl> |
| <dt>{@code inviteContactActivity}</dt> |
| <dd> |
| Полное имя класса операции в вашем приложении, которую необходимо активировать |
| при выборе пользователем элемента <strong>Добавить подключение</strong> в приложении |
| для работы с контактами, которое имеется на устройстве. |
| </dd> |
| <dt>{@code inviteContactActionLabel}</dt> |
| <dd> |
| Текстовая строка, которая отображается для операции, заданной в |
| {@code inviteContactActivity}, в меню <strong>Добавить подключение</strong>. |
| Например, можно указать фразу «Следите за новостями в моей сети». Для этого элемента можно использовать |
| идентификатор строкового ресурса. |
| </dd> |
| <dt>{@code viewContactNotifyService}</dt> |
| <dd> |
| Полное имя класса службы в вашем приложении, которая должна получать |
| уведомления при просмотре контакта пользователем. Такое уведомление отправляется приложением для работы с контактами, |
| которое имеется на устройстве; благодаря этому ваше приложение может отложить выполнение операций, требующих обработки большого объема данных, до тех пор |
| , пока это не потребуется. Например, ваше приложение может реагировать на такое уведомление |
| путем считывания и отображения фотографии контакта в высоком разрешении и самых актуальных |
| элементов потока данных из социальной сети. Дополнительные сведения об этой функции представлены в разделе |
| <a href="#SocialStreamInteraction">Взаимодействие с потоками данных из социальных сетей</a>. Пример |
| службы уведомлений представлен в файле |
| <code>NotifierService.java</code> в |
| образце приложения<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a>. |
| </dd> |
| <dt>{@code viewGroupActivity}</dt> |
| <dd> |
| Полное имя класса операции в вашем приложении, которая может отобразить |
| информацию о группе. При нажатии пользователем на метку группы в приложении для работы с данными, |
| которое имеется на устройстве, отображается пользовательский интерфейс для этой операции. |
| </dd> |
| <dt>{@code viewGroupActionLabel}</dt> |
| <dd> |
| Метка, отображаемая приложением для работы с контактами для элемента пользовательского интерфейса, с помощью которой |
| пользователь может просмотреть группы в вашем приложении. |
| <p> |
| Например, если вы установили приложение Google+ на ваше устройство и выполняете синхронизацию |
| данных в Google+ с приложением для работы с контактами, то круги Google+ будут обозначены в приложении для работы с контактами как |
| группы на вкладке <strong>Группы</strong>. При нажатии на на круг |
| Google+ участники крга отобразятся как группа контактов. В верхней части экрана |
| находится значок Google+; если нажать на него, управление перейдет в приложение |
| Google+. В приложении для управления контактами это реализовано с помощью |
| {@code viewGroupActivity}, в которой значок Google+ используется в качестве значения |
| {@code viewGroupActionLabel}. |
| </p> |
| <p> |
| Для этого атрибута можно использовать идентификатор строкового ресурса. |
| </p> |
| </dd> |
| <dt>{@code viewStreamItemActivity}</dt> |
| <dd> |
| Полное имя класса операции в вашем приложении, которую запускает |
| приложение для работы с контактами, когда пользователь выбирает элемент потока для необработанного контакта. |
| </dd> |
| <dt>{@code viewStreamItemPhotoActivity}</dt> |
| <dd> |
| Полное имя класса операции в вашем приложении, которую запускает |
| приложение для работы с контактами, когда пользователь выбирает фотографию в элементе |
| потока для необработанного контакта. |
| </dd> |
| </dl> |
| <h4 id="SocialStreamDataKind">Элемент <ContactsDataKind></h4> |
| <p> |
| Элемент <code><ContactsDataKind></code> управляет отображением настраиваемых строк данных вашего |
| приложения в интерфейсе приложения для работы с контактами, которое имеется на устройстве. Ниже представлен его синтаксис. |
| </p> |
| <pre> |
| <ContactsDataKind |
| android:mimeType="<em>MIMEtype</em>" |
| android:icon="<em>icon_resources</em>" |
| android:summaryColumn="<em>column_name</em>" |
| android:detailColumn="<em>column_name</em>"> |
| </pre> |
| <p> |
| <strong>находится в:</strong> |
| </p> |
| <code><ContactsAccountType></code> |
| <p> |
| <strong>Описание</strong> |
| </p> |
| <p> |
| Используйте этот элемент для отображения содержимого настраиваемой строки данных в приложении для работы с контактами как части |
| сведений о необработанном контакте. Каждый дочерний элемент <code><ContactsDataKind></code> |
| элемента <code><ContactsAccountType></code> представляет собой тип настраиваемой строки данных, который |
| адаптер синхронизации добавляет в таблицу {@link android.provider.ContactsContract.Data}. Для каждого используемого вами настраиваемого типа MIME необходимо добавить один элемент |
| <code><ContactsDataKind></code>. Вам не нужно добавлять элемент |
| , если у вас имеется настраиваемая строка данных, для которой не требуется отображать данные. |
| </p> |
| <p> |
| <strong>Атрибуты</strong> |
| </p> |
| <dl> |
| <dt>{@code android:mimeType}</dt> |
| <dd> |
| Определенные вами настраиваемые типы MIME для одного из ваших типов настраиваемых строк данных в таблице |
| {@link android.provider.ContactsContract.Data}. Например, значение |
| <code>vnd.android.cursor.item/vnd.example.locationstatus</code> может быть настраиваемым |
| типом MIME для строки данных, в которой находятся записи о последнем известном местоположении контакта. |
| </dd> |
| <dt>{@code android:icon}</dt> |
| <dd> |
| <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Графический ресурс </a> |
| Android, |
| который приложение для работы с контактами отображает рядом с вашими данными. Используйте его для обозначения того, |
| что эти данные получены из вашей службы. |
| </dd> |
| <dt>{@code android:summaryColumn}</dt> |
| <dd> |
| Имя столбца для первого из двух значений, полученных из строки данных. Значение |
| отображается в виде первой строки записи в этой строке данных. Первая строка |
| предназначена для использования в качестве сводных данных, однако она необязательна. См. также |
| <a href="#detailColumn">android:detailColumn</a>. |
| </dd> |
| <dt>{@code android:detailColumn}</dt> |
| <dd> |
| Имя столбца для второго из двух значений, полученных из строки данных. Значение |
| отображается в виде второй строки записи в этой строке данных. См. также |
| {@code android:summaryColumn}. |
| </dd> |
| </dl> |
| <h2 id="AdditionalFeatures">Дополнительные возможности поставщика контактов</h2> |
| <p> |
| Помимо основных функций, описанных разделах выше, в поставщике |
| контактов предусмотрены указанные ниже полезные функции для работы с данными контактов. |
| </p> |
| <ul> |
| <li>Группы контактов</li> |
| <li>Функции работы с фотографиями</li> |
| </ul> |
| <h3 id="Groups">Группы контактов</h3> |
| <p> |
| Поставщик контактов может дополнительно отметить коллекции связанных контактов с данными о |
| <strong>группе</strong>. Если серверу, который связан с учетной записью пользователя, |
| требуется сохранить группы, адаптеру синхронизации для типа этого аккаунта следует передать |
| данные о группах из поставщика контактов на сервер. При добавлении пользователем нового контакта на сервер |
| и последующем помещении этого контакта в новую группу адаптер синхронизации должен добавить эту новую группу в таблицу |
| {@link android.provider.ContactsContract.Groups}. Группа или группы, в которые входит необработанный контакт, |
| хранятся в таблице {@link android.provider.ContactsContract.Data} с использованием типа MIME |
| {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}. |
| </p> |
| <p> |
| Если необходимо создать адаптер синхронизации, который будет добавлять данные необработанного контакта с сервера |
| в поставщик контактов, а вы не используете группы, то вам необходимо указать для поставщика, |
| чтобы он сделал ваши данные видимыми. В коде, который выполняется при добавлении пользователем |
| аккаунта на устройство, обновите строку {@link android.provider.ContactsContract.Settings}, |
| которую поставщик контактов добавляет для этого аккаунта. В этой строке укажите в столбце |
| {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE |
| Settings.UNGROUPED_VISIBLE} значение «1». После этого поставщик контактов всегда будет |
| делать ваши данные видимыми, даже если вы не используете группы. |
| </p> |
| <h3 id="Photos">Фотографии контактов</h3> |
| <p> |
| В таблице {@link android.provider.ContactsContract.Data} хранятся фотографии в виде строк |
| {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE |
| Photo.CONTENT_ITEM_TYPE} типа MIME. Столбец |
| {@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} в строке связан со столбцом |
| {@code android.provider.BaseColumns#_ID} необработанного контакта, которому он принадлежит. |
| Класс {@link android.provider.ContactsContract.Contacts.Photo} определяет вложенную таблицу |
| {@link android.provider.ContactsContract.Contacts}, в которой содержится информация об основной фотографии |
| контакта (которая является основной фотографией основного необработанного контакта этого контакта). Аналогичным образом класс |
| {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} определяет вложенную таблицу |
| {@link android.provider.ContactsContract.RawContacts}, в которой содержится информация об основной фотографии |
| необработанного контакта. |
| </p> |
| <p> |
| В справочной документации по {@link android.provider.ContactsContract.Contacts.Photo} и |
| {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} содержатся примеры |
| получения информации о фотографии. К сожалению, отсутствует класс для удобного извлечения миниатюры |
| основной фотографии необработанного контакта, однако вы можете отправить запрос в таблицу |
| {@link android.provider.ContactsContract.Data}, выбрать |
| {@code android.provider.BaseColumns#_ID} необработанного контакта, |
| {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE |
| Photo.CONTENT_ITEM_TYPE} и столбец {@link android.provider.ContactsContract.Data#IS_PRIMARY}, |
| чтобы найти строку основной фотографии необработанного контакта. |
| </p> |
| <p> |
| Потоки данных из социальных сетей также могут включать фотографии. Они находятся в таблице |
| {@code android.provider.ContactsContract.StreamItemPhotos}, дополнительные сведения о которой представлены в разделе |
| <a href="#StreamPhotos">Фотографии из потока данных из социальных сетей</a>. |
| </p> |