• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Поставщик контактов
2@jd:body
3<div id="qv-wrapper">
4<div id="qv">
5<h2>Краткое описание</h2>
6<ul>
7    <li>Репозиторий Android с пользовательскими данными.</li>
8    <li>
9        Синхронизация со службами в Интернете.
10    </li>
11    <li>
12        Интеграция с потоками данных из социальных сетей.
13    </li>
14</ul>
15<h2>Содержание документа</h2>
16<ol>
17    <li>
18        <a href="#InformationTypes">Структура поставщика контактов</a>
19    </li>
20    <li>
21        <a href="#RawContactBasics">Необработанные контакты</a>
22    </li>
23    <li>
24        <a href="#DataBasics">Данные</a>
25    </li>
26    <li>
27        <a href="#ContactBasics">Контакты</a>
28    </li>
29    <li>
30        <a href="#Sources">Данные, полученные от адаптеров синхронизации</a>
31    </li>
32    <li>
33        <a href="#Permissions">Требуемые разрешения</a>
34    </li>
35    <li>
36        <a href="#UserProfile">Профиль пользователя</a>
37    </li>
38    <li>
39        <a href="#ContactsProviderMetadata">Метаданные поставщика контактов</a>
40    </li>
41    <li>
42        <a href="#Access">Доступ к поставщику контактов</a>
43    <li>
44    </li>
45    <li>
46        <a href="#SyncAdapters">Адаптеры синхронизации поставщика контактов</a>
47    </li>
48    <li>
49        <a href="#SocialStream">Потоки данных из социальных сетей</a>
50    </li>
51    <li>
52        <a href="#AdditionalFeatures">Дополнительные возможности поставщика контактов</a>
53    </li>
54</ol>
55<h2>Ключевые классы</h2>
56<ol>
57    <li>{@link android.provider.ContactsContract.Contacts}</li>
58    <li>{@link android.provider.ContactsContract.RawContacts}</li>
59    <li>{@link android.provider.ContactsContract.Data}</li>
60    <li>{@code android.provider.ContactsContract.StreamItems}</li>
61</ol>
62<h2>Образцы кода по теме</h2>
63<ol>
64    <li>
65        <a href="{@docRoot}resources/samples/ContactManager/index.html">
66Диспетчер контактов
67</a>
68    </li>
69    <li>
70        <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
71Пример адаптера синхронизации</a>
72    </li>
73</ol>
74<h2>См. также:</h2>
75<ol>
76    <li>
77        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
78Основные сведения о поставщике контента
79</a>
80    </li>
81</ol>
82</div>
83</div>
84<p>
85    Поставщик контактов представляет собой эффективный и гибкий компонент Android, который управляет
86центральным репозиторием устройства, в котором хранятся пользовательские данные. Поставщик контактов — это источник данных,
87которые отображаются в приложении «Контакты» на вашем устройстве. Вы также можете получить доступ к этим данным в своем собственном
88приложении и организовать обмен такими данными между устройством и службами в Интернете. Поставщик взаимодействует
89с широким набором источников данных и пытается организовать управление как можно большим набором данных о каждом человеке, поэтому
90организация поставщика довольно сложная. По этой причине API поставщика
91содержит широкий набор классов-контрактов и интерфейсов, отвечающих как за получение данных, так и за их
92изменение.
93</p>
94<p>
95    В этом руководстве рассматриваются следующие вопросы:
96</p>
97    <ul>
98        <li>
99            основная структура поставщика;
100        </li>
101        <li>
102            порядок получения данных от поставщика;
103        </li>
104        <li>
105            порядок изменения данных в поставщике;
106        </li>
107        <li>
108            порядок записи адаптера синхронизации для синхронизации данных, полученных с вашего сервера, с данными в
109поставщике контактов.
110        </li>
111    </ul>
112<p>
113    При изучении данного материала подразумевается, что вы уже знакомы с основами поставщиков контента Android. Дополнительные сведения
114о поставщиках контента Android представлены в руководстве
115<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Основные
116сведения о поставщике контента</a>. Пример
117<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">адаптера синхронизации</a>
118служит примером использования такого приложения для обмена данными между поставщиком
119контактов и приложением, размещенным в веб-службах Google.
120</p>
121<h2 id="InformationTypes">Структура поставщика контактов</h2>
122<p>
123    Поставщик контактов представляет собой поставщик контента Android. Он содержит в себе три типа
124данных о пользователе, каждый из которых указан в отдельной таблице, предоставляемой поставщиком,
125как показано на рисунке 1.
126</p>
127<img src="{@docRoot}images/providers/contacts_structure.png" alt="" height="364" id="figure1" />
128<p class="img-caption">
129  <strong>Рисунок 1.</strong> Структура таблицы поставщика контактов.
130</p>
131<p>
132    В качестве имен этих трех таблиц обычно используются названия соответствующих классов-контрактов. Эти классы
133определяют константы для URI контента, названий столбцов и значений в столбцах этих таблиц.
134</p>
135<dl>
136    <dt>
137        Таблица {@link android.provider.ContactsContract.Contacts}
138    </dt>
139    <dd>
140        Строки в этой таблице содержат данные о разных пользователях, полученные путем агрегации строк необработанных контактов.
141    </dd>
142    <dt>
143        Таблица {@link android.provider.ContactsContract.RawContacts}
144    </dt>
145    <dd>
146        Строки в этой таблице содержат сводные данные о пользователе, относящиеся к пользовательскому аккаунту и его типу.
147    </dd>
148    <dt>
149        Таблица {@link android.provider.ContactsContract.Data}
150    </dt>
151    <dd>
152        Строки в этой таблице содержат сведения о необработанных контактах, такие как адреса эл. почты или номера телефонов.
153    </dd>
154</dl>
155<p>
156    Другие таблицы, представленные классами-контрактами в {@link android.provider.ContactsContract},
157представляют собой вспомогательные таблицы, которые поставщик контактов использует для управления своими операциями или поддержки
158определенных функций, имеющихся в приложении устройства «Контакты» или приложениях для телефонной связи.
159</p>
160<h2 id="RawContactBasics">Необработанные контакты</h2>
161<p>
162    Необработанный контакт представляет собой данные о пользователе, поступающие из одного аккаунта определенного
163типа. Поскольку в качестве источника данных о пользователе в поставщике контактов может выступать сразу несколько онлайн-служб,
164для одного и того же пользователя в поставщике контактов может существовать несколько необработанных контактов.
165    Это также позволяет пользователю объединять пользовательские данные из нескольких аккаунтов
166одного и того же типа.
167</p>
168<p>
169    Большая часть данных необработанного контакта не хранится в таблице
170{@link android.provider.ContactsContract.RawContacts}. Вместо этого они хранятся в одной или нескольких
171строках в таблице {@link android.provider.ContactsContract.Data}. В каждой строке данных имеется
172столбец {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID},
173в котором содержится значение {@code android.provider.BaseColumns#_ID RawContacts._ID} его
174родительской строки{@link android.provider.ContactsContract.RawContacts}.
175</p>
176<h3 id="RawContactsColumns">Важные столбцы необработанных контактов</h3>
177<p>
178    В таблице 1 указаны столбцы таблицы {@link android.provider.ContactsContract.RawContacts},
179которые имеют большое значение. Обязательно ознакомьтесь с примечаниями, приведенными после этой таблицы.
180</p>
181<p class="table-caption" id="table1">
182    <strong>Таблица 1.</strong> Важные столбцы необработанных контактов.
183</p>
184<table>
185    <tr>
186        <th scope="col">Название столбца</th>
187        <th scope="col">Использование</th>
188        <th scope="col">Примечания</th>
189    </tr>
190    <tr>
191        <td>
192            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME}
193        </td>
194        <td>
195            Имя аккаунта для типа аккаунта, который выступает в роли источника данных для необработанного контакта.
196            Например, имя аккаунта Google является одним из эл. адресов почты Gmail
197владельца устройства. Дополнительные сведения
198см. в следующей записи
199{@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE}.
200        </td>
201        <td>
202            Формат этого имени зависит от типа аккаунта. Это не обязательно
203адрес эл. почты.
204        </td>
205    </tr>
206    <tr>
207        <td>
208            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE}
209        </td>
210        <td>
211            Тип аккаунта, который выступает в роли источника данных для необработанного контакта. Например, тип аккаунта
212Google — <code>com.google</code>. Всегда указывайте тип аккаунта
213и идентификатор домена, которым вы владеете или управляете. Это позволит гарантировать уникальность
214типа вашего аккаунта.
215        </td>
216        <td>
217            У типа аккаунта, выступающего в роли источника данных контактов, обычно имеется связанный с ним адаптер синхронизации,
218который синхронизирует данные с поставщиком контактов.
219    </tr>
220    <tr>
221        <td>
222            {@link android.provider.ContactsContract.RawContactsColumns#DELETED}
223        </td>
224        <td>
225            Флаг deleted для необработанного контакта.
226        </td>
227        <td>
228            Этот флаг позволяет поставщику контактов хранить строку внутри себя до тех пор,
229пока адаптеры синхронизации не смогут удалить эту строку с серверов, а затем
230удалить ее из репозитория.
231        </td>
232    </tr>
233</table>
234<h4>Примечания</h4>
235<p>
236    Ниже представлены важные примечания к таблице
237{@link android.provider.ContactsContract.RawContacts}.
238</p>
239<ul>
240    <li>
241        Имя необработанного контакта не хранится в его строке в таблице
242{@link android.provider.ContactsContract.RawContacts}. Вместо этого оно хранится в
243таблице {@link android.provider.ContactsContract.Data}
244в строке {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}. У необработанного контакта
245имеется в таблице {@link android.provider.ContactsContract.Data} только одна строка такого типа.
246    </li>
247    <li>
248        <strong>Внимание!</strong> Чтобы использовать в строке необработанного контакта данные собственного аккаунта, строку
249, сначала необходимо зарегистрировать его в классе {@link android.accounts.AccountManager}. Для этого предложите
250пользователям добавить тип аккаунта и его имя в список аккаунтов. Если
251не сделать этого, поставщик контактов автоматически удалит вашу строку необработанного контакта.
252        <p>
253            Например, если необходимо, чтобы в вашем приложении хранились данные контактов для веб-службы
254в домене {@code com.example.dataservice}, и аккаунт пользователя службы
255 выглядит следующим образом:{@code becky.sharp@dataservice.example.com}, то пользователю сначала необходимо добавить
256«тип» аккаунта ({@code com.example.dataservice}) и его «имя»
257({@code becky.smart@dataservice.example.com}) прежде чем ваше приложение сможет добавлять строки необработанных контактов.
258            Это требование можно указать в документации для пользователей, а также можно предложить
259пользователю добавить тип и имя своего аккаунта, либо реализовать оба этих варианта. Более подробно типы и имена аккаунтов
260рассматриваются в следующем разделе.
261    </li>
262</ul>
263<h3 id="RawContactsExample">Источники данных необработанных контактов</h3>
264<p>
265    Чтобы понять, что такое необработанный контакт, рассмотрим пример с пользователем Emily Dickinson, на устройстве которой имеется три
266следующих аккаунта:
267</p>
268<ul>
269    <li><code>emily.dickinson@gmail.com</code>;</li>
270    <li><code>emilyd@gmail.com</code>;</li>
271    <li>Аккаунт belle_of_amherst в Twitter</li>
272</ul>
273<p>
274    Она включила функцию <em>Синхронизировать контакты</em> для всех трех этих аккаунтов
275в настройках <em>Аккаунты</em>.
276</p>
277<p>
278    Предположим, что Emily Dickinson открывает браузер, входит в Gmail под именем
279<code>emily.dickinson@gmail.com</code>, затем открывает
280Контакты и добавляет новый контакт Thomas Higginson. Позже она снова входит в Gmail под именем
281<code>emilyd@gmail.com</code> и отправляет письмо пользователю Thomas Higginson, который автоматически
282добавляется в ее контакты. Также она подписана на новости от colonel_tom (аккаунт пользователя Thomas Higginson в Twitter) в
283Twitter.
284</p>
285<p>
286    В результате этих действий поставщик контактов создает три необработанных контакта:
287</p>
288<ol>
289    <li>
290        Необработанный контакт Thomas Higginson связан с аккаунтом <code>emily.dickinson@gmail.com</code>.
291        Тип этого аккаунта — Google.
292    </li>
293    <li>
294        Второй необработанный контакт Thomas Higginson связан с аккаунтом <code>emilyd@gmail.com</code>.
295        Тип этого аккаунта — также Google. Второй необработанный контакт создается даже в том случае,
296если его имя полностью совпадает с именем предыдущего контакта, поскольку первый
297был добавлен для другого аккаунта.
298    </li>
299    <li>
300        Третий необработанный контакт Thomas Higginson связан с аккаунтом belle_of_amherst. Тип этого аккаунта
301— Twitter.
302    </li>
303</ol>
304<h2 id="DataBasics">Данные</h2>
305<p>
306    Как уже указывалось ранее, данные необработанного контакта
307хранятся в строке {@link android.provider.ContactsContract.Data}, которая связана со значением
308<code>_ID</code> необработанного контакта. Благодаря этому для одного необработанного контакта может существовать несколько экземпляров
309одного и того же типа данных (например, адресов эл. почты или номеров телефонов). Например, если у контакта
310Thomas Higginson для аккаунта {@code emilyd@gmail.com} (строка необработанного контакта Thomas Higginson,
311связанная с учетной записью Google <code>emilyd@gmail.com</code>) имеется адрес эл. почты
312<code>thigg@gmail.com</code> и служебный адрес эл. почты
313<code>thomas.higginson@gmail.com</code>, то поставщик контактов сохраняет две строки
314адреса эл. почты и связывает их с этим необработанным контактом.
315</p>
316<p>
317    Обратите внимание, что в этой таблице хранятся данные разных типов. Строки со сведениями об отображаемом имени,
318номере телефона, адресе эл. почты, почтовом адресе, фото и веб-сайте хранятся в таблице
319{@link android.provider.ContactsContract.Data}. Для упрощения управления этими данными в таблице
320{@link android.provider.ContactsContract.Data} предусмотрены столбцы с описательными именами,
321а также другие столбцы с универсальными именами. Содержимое в столбце с описательным именем имеет то же значение,
322независимо от типа данных в строке, тогда как содержимое столбца с универсальным именем
323может иметь разное значение в зависимости от типа данных.
324</p>
325<h3 id="DescriptiveColumns">Описательные имена столбцов</h3>
326<p>
327    Вот некоторые примеры столбцов с описательными именами:
328</p>
329<dl>
330    <dt>
331        {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID}
332    </dt>
333    <dd>
334        Значение в столбце <code>_ID</code> необработанного контакта для этих данных.
335    </dd>
336    <dt>
337        {@link android.provider.ContactsContract.Data#MIMETYPE}
338    </dt>
339    <dd>
340        Тип данных, хранящихся в этой строке, в виде настраиваемого типа MIME. Поставщик контактов
341использует типы MIME, заданные в подклассах класса
342{@link android.provider.ContactsContract.CommonDataKinds}. Эти типы MIME являются открытыми, и
343их может использовать любое приложение или адаптер синхронизации, поддерживающие работу с поставщиком контактов.
344    </dd>
345    <dt>
346        {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
347    </dt>
348    <dd>
349        Если этот тип данных для необработанного контакта встречается несколько раз, то
350столбец {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} помечает флагом
351строки данных, в которых содержатся основные данные для этого типа. Например, если
352пользователь нажал и удерживает номер телефона контакта и выбрал параметр <strong>Использовать по умолчанию</strong>,
353то в столбце {@link android.provider.ContactsContract.Data} с этим номером телефона
354в соответствующем столбце {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} задается
355значение, отличное от нуля.
356    </dd>
357</dl>
358<h3 id="GenericColumns">Универсальные имена столбцов</h3>
359<p>
360    Существует 15 общедоступных столбцов с универсальными именами (<code>DATA1</code>–<code>DATA15</code>)
361и четыре дополнительных столбца
362(<code>SYNC1</code>–<code>SYNC4</code>), которые используются только адаптерами
363синхронизации. Константы столбцов с универсальными именами применяются всегда, независимо от типа данных,
364содержащихся в столбце.
365</p>
366<p>
367    Столбец <code>DATA1</code> является индексируемым.  Поставщик контактов всегда использует этот столбец для
368данных, которые, как он ожидает, будут наиболее часто являться целевыми в запросах. Например,
369в строке с адресами эл. почты в этом столбце указывается фактический адрес эл. почты.
370</p>
371<p>
372    Обычно столбец <code>DATA15</code> зарезервирован для данных больших двоичных объектов
373(BLOB), таких как миниатюры фотографий.
374</p>
375<h3 id="TypeSpecificNames">Имена столбцов по типам строк</h3>
376<p>
377    Для упрощения работы со столбцами определенного типа строк в поставщике контактов
378также предусмотрены константы для имен столбцов по типам строк, которые определены в подклассах класса
379{@link android.provider.ContactsContract.CommonDataKinds}. Эти константы просто
380присваивают одному и тому же имени столбца различные константы, что позволяет вам получать доступ к данным в строке
381определенного типа.
382</p>
383<p>
384    Например, класс {@link android.provider.ContactsContract.CommonDataKinds.Email} определяет
385константы имени столбца для строки {@link android.provider.ContactsContract.Data},
386в которой имеется тип MIME
387{@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
388Email.CONTENT_ITEM_TYPE}. В этом классе содержится константа
389{@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} для столбца адреса
390эл. почты. Фактическое значение
391{@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} — data1, которое совпадает
392с универсальным именем столбца.
393</p>
394<p class="caution">
395    <strong>Внимание!</strong> Не добавляйте свои настраиваемые данные в таблицу
396{@link android.provider.ContactsContract.Data} с помощью строки, в которой имеется один из
397предварительно заданных поставщиком типов MIME. В противном случае вы можете потерять данные или вызвать неполадки
398в работе поставщика. Например, не следует добавлять строку с типом MIME
399{@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
400Email.CONTENT_ITEM_TYPE}, в которой в столбце
401<code>DATA1</code> вместо адреса эл. почты содержится имя пользователя. Если вы укажете в строке собственный настраиваемый тип MIME, вы можете свободно
402указывать собственные имена столбцов по типам строк и использовать их так, как пожелаете.
403</p>
404<p>
405    На рисунке 2 показано, как столбцы с описательными именами и столбцы данных отображаются в строке
406{@link android.provider.ContactsContract.Data}, а также как имена столбцов по типу строк «накладываются»
407на универсальные имена столбцов.
408</p>
409<img src="{@docRoot}images/providers/data_columns.png" alt="How type-specific column names map to generic column names" height="311" id="figure2" />
410<p class="img-caption">
411  <strong>Рисунок 2.</strong> Имена столбцов по типам строк и универсальные имена столбцов.
412</p>
413<h3 id="ColumnMaps">Классы имен столбцов по типам строк</h3>
414<p>
415    В таблице 2 перечислены наиболее часто используемые классы имен столбцов по типам строк.
416</p>
417<p class="table-caption" id="table2">
418  <strong>Таблица 2.</strong> Классы имен столбцов по типам строк</p>
419<table>
420  <tr>
421    <th scope="col">Класс сопоставления</th>
422    <th scope="col">Тип данных</th>
423    <th scope="col">Примечания</th>
424  </tr>
425  <tr>
426    <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredName}</td>
427    <td>Данные об имени необработанного контакта, связанного с этой строкой данных.</td>
428    <td>У необработанного контакта имеется только одна строка такого типа.</td>
429  </tr>
430  <tr>
431    <td>{@link android.provider.ContactsContract.CommonDataKinds.Photo}</td>
432    <td>Основная фотография необработанного контакта, связанного с этой строкой данных.</td>
433    <td>У необработанного контакта имеется только одна строка такого типа.</td>
434  </tr>
435  <tr>
436    <td>{@link android.provider.ContactsContract.CommonDataKinds.Email}</td>
437    <td>Адрес эл. почты необработанного контакта, связанного с этой строкой данных.</td>
438    <td>У необработанного контакта может быть несколько адресов эл. почты.</td>
439  </tr>
440  <tr>
441    <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal}</td>
442    <td>Почтовый адрес необработанного контакта, связанного с этой строкой данных.</td>
443    <td>У необработанного контакта может быть несколько почтовых адресов.</td>
444  </tr>
445  <tr>
446    <td>{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}</td>
447    <td>Идентификатор, с помощью которого необработанный контакт связан с одной из групп в поставщике контактов.</td>
448    <td>
449        Группы представляют собой необязательный компонент для типа аккаунта и имени аккаунта. Дополнительные сведения о
450группах представлены в разделе <a href="#Groups">Группы контактов</a>.
451    </td>
452  </tr>
453</table>
454<h3 id="ContactBasics">Контакты</h3>
455<p>
456    Поставщик контактов объединяет строки с необработанными контактами для всех типов аккаунтов и имен аккаунтов
457для создания <strong>контакта</strong>. Это позволяет упростить отображение и изменение всех данных,
458собранных в отношении пользователя. Поставщик контактов управляет процессом создания строк
459контактов и агрегированием необработанных контактов, у которых имеется строка контакта. Ни приложениям, ни
460адаптерам синхронизации не разрешается добавлять контакты, а некоторые столбцы в строке контакта доступны только для чтения.
461</p>
462<p class="note">
463    <strong>Примечание.</strong> Если попытаться добавить контакт в поставщик контактов с помощью метода
464{@link android.content.ContentResolver#insert(Uri,ContentValues) insert()}, будет выдано исключение
465{@link java.lang.UnsupportedOperationException}. Если вы попытаетесь обновить столбец,
466доступный только для чтения, это действие будет проигнорировано.
467</p>
468<p>
469    При добавлении нового необработанного контакта,
470который не соответствует ни одному из существующих контактов, поставщик контактов создает новый контакт. Поставщик поступает аналогично в случае, если
471данные в строке существующего необработанного контакта изменяются таким образом, что они больше не соответствуют контакту,
472с которым они ранее были связаны. При создании приложением или адаптером синхронизации нового контакта,
473который <em></em> соответствует существующему контакту, то новый контакт объединяется с
474существующим контактом.
475</p>
476<p>
477    Поставщик контактов связывает строку контакта с его строками необработанного контакта посредством столбца
478<code>_ID</code> строки контакта в таблице
479{@link android.provider.ContactsContract.Contacts Contacts}. Столбец <code>CONTACT_ID</code> в таблице необработанных контактов
480{@link android.provider.ContactsContract.RawContacts} содержит значения <code>_ID</code> для
481строки контактов, связанной с каждой строкой необработанных контактов.
482</p>
483<p>
484    В таблице {@link android.provider.ContactsContract.Contacts} также имеется столбец
485{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}, который выступает в роли
486«постоянной ссылки» на строку контакта. Поскольку поставщик контактов автоматически сохраняет контакты,
487в ответ на агрегирование или синхронизацию он может изменить значение {@code android.provider.BaseColumns#_ID}
488строки контакта. Даже если это произойдет, URI контента
489{@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, объединенный с
490{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} контакта, будет
491по-прежнему указывать на строку контакта, поэтому вы можете смело использовать
492{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
493для сохранения ссылок на «избранные» контакты и др. Столбец имеет собственный формат,
494который не связан с форматом столбца{@code android.provider.BaseColumns#_ID}.
495</p>
496<p>
497    На рисунке 3 показаны взаимосвязи этих трех основных таблиц друг с другом.
498</p>
499<img src="{@docRoot}images/providers/contacts_tables.png" alt="Contacts provider main tables" height="514" id="figure4" />
500<p class="img-caption">
501  <strong>Рисунок 3</strong>. Взаимосвязи между таблицами контактов, необработанных контактов и сведений.
502</p>
503<h2 id="Sources">Данные, полученные от адаптеров синхронизации</h2>
504<p>
505    Пользователь вводит данные контактов прямо на устройстве, однако данные также поступают в поставщик контактов
506из веб-служб посредством <strong>адаптеров синхронизации</strong>, что позволяет автоматизировать
507обмен данными между устройством и службами в Интернете. Адаптеры синхронизации выполняются в фоновом режиме под
508управлением системы, и для управления данными они вызывают методы
509{@link android.content.ContentResolver}.
510</p>
511<p>
512    В Android веб-служба, с которой работает адаптер синхронизации, определяется по типу аккаунта.
513    Каждый адаптер синхронизации работает с одним типом аккаунта, однако он может поддерживать несколько имен аккаунтов
514такого типа. Вкратце типы и имена аккаунтов рассматриваются
515в разделе <a href="#RawContactsExample">Источники данных необработанных контактов</a>. Указанные ниже определения позволяют
516более точно охарактеризовать связь между типами и именами аккаунтов и адаптерами синхронизации и службами.
517</p>
518<dl>
519    <dt>
520        Тип аккаунта
521    </dt>
522    <dd>
523        Определяет службу, в которой пользователь хранит данные. В большинстве случаев для работы со
524службой пользователю необходимо пройти проверку подлинности. Например, Google Контакты представляет собой тип аккаунтов, обозначаемый кодом
525<code>google.com</code>. Это значение соответствует типу аккаунта, используемого
526{@link android.accounts.AccountManager}.
527    </dd>
528    <dt>
529        Имя аккаунта
530    </dt>
531    <dd>
532        Определяет конкретный аккаунт или имя для входа для типа аккаунта. Аккаунты «Контакты Google»
533— это то же, что и аккаунты Google, в качестве имени которых используется адрес эл. почты.
534        В других службах может использоваться имя пользователя, состоящее из одного слова, или числовой идентификатор.
535    </dd>
536</dl>
537<p>
538    Типы аккаунтов не обязательно должны быть уникальными. Пользователь может создать несколько аккаунтов Google Контакты
539и загрузить данные из них в поставщик контактов; это может произойти в случае, если у пользователя имеется один набор
540персональных контактов для личного аккаунта, и другой набор — для служебного аккаунта. Имена
541аккаунтов обычно уникальные. Вместе они формируют определенный поток данных между поставщиком контактов
542и внешними службами.
543</p>
544<p>
545    Если необходимо передать данные из службы в поставщик контактов, необходимо создать
546собственный адаптер синхронизации. Дополнительные сведения об этом представлены в разделе
547<a href="#SyncAdapters">Адаптеры синхронизации поставщика контактов</a>.
548</p>
549<p>
550    На рисунке 4 показано, какую роль выполняет поставщик контактов в потоке передачи данных
551о пользователях. В области, отмеченной на рисунке как sync adapters, каждый адаптер промаркирован в соответствии с поддерживаемым им типом аккаунтов.
552</p>
553<img src="{@docRoot}images/providers/ContactsDataFlow.png" alt="Flow of data about people" height="252" id="figure5" />
554<p class="img-caption">
555  <strong>Рисунок 4</strong>. Поток передачи данных через поставщика контактов.
556</p>
557<h2 id="Permissions">Требуемые разрешения</h2>
558<p>
559    Приложения, которым требуется доступ к поставщику контактов,
560должны запросить указанные ниже разрешения.
561</p>
562<dl>
563    <dt>Доступ на чтение одной или нескольких таблиц</dt>
564    <dd>
565        {@link android.Manifest.permission#READ_CONTACTS}, указанный в файле
566<code>AndroidManifest.xml</code> с элементом
567<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
568        &lt;uses-permission&gt;</a></code> в виде
569<code>&lt;uses-permission android:name="android.permission.READ_CONTACTS"&gt;</code>.
570    </dd>
571    <dt>Доступ на запись в одну или несколько таблиц</dt>
572    <dd>
573        {@link android.Manifest.permission#WRITE_CONTACTS}, указанный в файле
574<code>AndroidManifest.xml</code> с элементом
575<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
576        &lt;uses-permission&gt;</a></code> в виде
577<code>&lt;uses-permission android:name="android.permission.WRITE_CONTACTS"&gt;</code>.
578    </dd>
579</dl>
580<p>
581    Эти разрешения не распространяются на работу с данными профиля пользователя. Профиль пользователя
582и требуемые разрешения для работы с ним рассматриваются в разделе
583<a href="#UserProfile">Профиль пользователя</a> ниже.
584</p>
585<p>
586    Помните, что данные о контактах пользователя являются личными и конфиденциальными. Пользователи заботятся о своей конфиденциальности,
587поэтому не хотят, чтобы приложения собирали данные о них самих или их контактах.
588    Если пользователю не до конца ясно, для чего требуется разрешение на доступ к данным контактов, они могут присвоить
589вашему приложению низкий рейтинг или вообще откажутся его устанавливать.
590</p>
591<h2 id="UserProfile">Профиль пользователя</h2>
592<p>
593    В таблице {@link android.provider.ContactsContract.Contacts} имеется всего одна строка, содержащая
594данные профиля для устройства пользователя. Эти данные описывают <code>user</code> устройства,
595а не один из контактов пользователя. Строка контактов профиля связана со строкой
596необработанных контактов в каждой из систем, в которой используется профиль.
597    В каждой строке необработанного контакта профиля может содержаться несколько строк данных. Константы для доступа к профилю пользователя
598представлены в классе {@link android.provider.ContactsContract.Profile}.
599</p>
600<p>
601    Для доступа к профилю пользователя требуются особые разрешения. Кроме разрешений
602{@link android.Manifest.permission#READ_CONTACTS} и
603{@link android.Manifest.permission#WRITE_CONTACTS}, которые требуются для чтения и записи, для доступа к профилю пользователя необходимы разрешения
604{@code android.Manifest.permission#READ_PROFILE} и
605{@code android.Manifest.permission#WRITE_PROFILE}
606на чтение и запись соответственно.
607</p>
608<p>
609    Всегда следует помнить, что профиль пользователя представляет собой конфиденциальную информацию. Разрешение
610{@code android.Manifest.permission#READ_PROFILE} предоставляет вам доступ к личной информации на устройстве
611пользователя. В описании своего приложения обязательно укажите, для
612чего вам требуется доступ к профилю пользователя.
613</p>
614<p>
615    Чтобы получить строку контакта с профилем пользователя, вызовите метод
616{@link android.content.ContentResolver#query(Uri,String[], String, String[], String)
617ContentResolver.query()}. Задайте для URI контента значение
618{@link android.provider.ContactsContract.Profile#CONTENT_URI} и не указывайте никаких критериев
619выборки. Этот URI контента также можно использовать в качестве основного URI для получения
620необработанных контактов или данных профиля. Ниже представлен фрагмент кода для получения данных профиля.
621</p>
622<pre>
623// Sets the columns to retrieve for the user profile
624mProjection = new String[]
625    {
626        Profile._ID,
627        Profile.DISPLAY_NAME_PRIMARY,
628        Profile.LOOKUP_KEY,
629        Profile.PHOTO_THUMBNAIL_URI
630    };
631
632// Retrieves the profile from the Contacts Provider
633mProfileCursor =
634        getContentResolver().query(
635                Profile.CONTENT_URI,
636                mProjection ,
637                null,
638                null,
639                null);
640</pre>
641<p class="note">
642    <strong>Примечание.</strong> Если при извлечении несколько строк контактов необходимо определить,
643какой из них является профилем пользователя, обратитесь к столбцу
644{@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} этой строки. Если в этом столбце
645указано значение «1», то в это строке находится профиль пользователя.
646</p>
647<h2 id="ContactsProviderMetadata">Метаданные поставщика контактов</h2>
648<p>
649    Поставщик контактов управляет данными, которые используются для отслеживания состояния данных контакта в
650репозитории. Эти метаданные о репозитории хранятся в различных местах, включая
651строки необработанных контактов, данные и строки таблицы контактов, таблицу
652{@link android.provider.ContactsContract.Settings} и таблицу
653{@link android.provider.ContactsContract.SyncState}. В таблице ниже
654указаны значения каждого из этих фрагментов метаданных.
655</p>
656<p class="table-caption" id="table3">
657  <strong>Таблица 3.</strong> Метаданные в поставщике контактов</p>
658<table>
659    <tr>
660        <th scope="col">Таблица</th>
661        <th scope="col">Столбец</th>
662        <th scope="col">Значения</th>
663        <th scope="col">Описание</th>
664    </tr>
665    <tr>
666        <td rowspan="2">{@link android.provider.ContactsContract.RawContacts}</td>
667        <td rowspan="2">{@link android.provider.ContactsContract.SyncColumns#DIRTY}</td>
668        <td>«0» — с момента последней синхронизации изменения не вносились.</td>
669        <td rowspan="2">
670            Служит для отметки необработанных контактов, которые были изменены на устройстве и которые необходимо снова синхронизировать с
671сервером. Значение устанавливается автоматически поставщиком контактов при обновлении строк приложениями
672Android.
673            <p>
674                Адаптеры синхронизации, которые вносят изменения в необработанные контакты или таблицы данных, должны всегда добавлять к используемому ими URI
675контента строку
676{@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER}. Это позволяет предотвратить пометку таких строк поставщиком как «грязных».
677                В противном случае изменения, внесенные адаптером синхронизации, будут рассматриваться как локальные изменения,
678которые подлежат отправке на сервер, даже если источником таких изменений был сам сервер.
679            </p>
680        </td>
681    </tr>
682    <tr>
683            <td>«1» — с момента последней синхронизации были внесены изменения, которые необходимо отразить и на сервере.</td>
684    </tr>
685    <tr>
686        <td>{@link android.provider.ContactsContract.RawContacts}</td>
687        <td>{@link android.provider.ContactsContract.SyncColumns#VERSION}</td>
688        <td>Номер версии этой строки.</td>
689        <td>
690            Поставщик контактов автоматически увеличивает это значение при каждом
691изменении в строке или в связанных с ним данных.
692        </td>
693    </tr>
694    <tr>
695        <td>{@link android.provider.ContactsContract.Data}</td>
696        <td>{@link android.provider.ContactsContract.DataColumns#DATA_VERSION}</td>
697        <td>Номер версии этой строки.</td>
698        <td>
699            Поставщик контактов автоматически увеличивает это значение при каждом
700изменении в строке данных.
701        </td>
702    </tr>
703    <tr>
704        <td>{@link android.provider.ContactsContract.RawContacts}</td>
705        <td>{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}</td>
706        <td>
707            Строковое значение, которое служит уникальным идентификатором данного необработанного контакта в аккаунте,
708в котором он был создан.
709        </td>
710        <td>
711            Когда адаптер синхронизации создает новый необработанный контакт, в этом столбце следует указать
712уникальный идентификатор этого необработанного контакта на сервере. Когда же приложение Android создает
713новый необработанный контакт, то приложению следует оставить этот столбец пустым. Это служит сигналом для
714адаптера синхронизации, чтобы создать новый необработанный контакт на сервере и
715получить значение {@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}.
716            <p>
717                В частности, идентификатор источника должен быть <strong>уникальным</strong> для каждого типа аккаунта
718и неизменным при синхронизации.
719            </p>
720                <ul>
721                    <li>
722                        Уникальный: у каждого необработанного контакта для аккаунта должен быть свой собственный идентификатор источника. Если
723не применить это требование, у вас обязательно возникнут проблемы с приложением «Контакты».
724                        Обратите внимание, что два необработанных контакта одного и того же <em>типа</em> аккаунта могут
725иметь одинаковый идентификатор источника. Например, необработанный контакт Thomas Higginson для
726аккаунта {@code emily.dickinson@gmail.com} может иметь такой же
727идентификатор источника, что и контакт Thomas Higginson для аккаунта
728{@code emilyd@gmail.com}.
729                    </li>
730                    <li>
731                        Стабильный: идентификаторы источников представляют собой неизменную часть данных онлайн-службы для
732необработанного контакта. Например, если пользователь выполняет повторную синхронизацию после очистки хранилища контактов в
733настройках приложения, идентификаторы источников восстановленных необработанных контактов должны быть такими же,
734как и прежде. Если не применить это требование, перестанут
735работать ярлыки.
736                    </li>
737                </ul>
738        </td>
739    </tr>
740    <tr>
741        <td rowspan="2">{@link android.provider.ContactsContract.Groups}</td>
742        <td rowspan="2">{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE}</td>
743        <td>«0» — контакты, представленные в этой группе, не должны отображаться в интерфейсах пользователя приложений Android.</td>
744        <td>
745            Этот столбец предназначен для сведений о совместимости с серверами, позволяющими пользователям скрывать контакты
746в определенных группах.
747        </td>
748    </tr>
749    <tr>
750        <td>«1» — контакты, представленные в этой группе, могут отображаться в интерфейсах пользователя приложений.</td>
751    </tr>
752    <tr>
753        <td rowspan="2">{@link android.provider.ContactsContract.Settings}</td>
754        <td rowspan="2">
755            {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE}</td>
756        <td>
757            «0» — для этого аккаунта и аккаунтов этого типа контакты, не принадлежащие к группе,
758не отображаются в интерфейсах пользователя приложений Android.
759        </td>
760        <td rowspan="2">
761            По умолчанию контакты скрыты, если ни один из их необработанных контактов не принадлежит группе
762(принадлежность необработанного контакта к группе указывается в одном или нескольких строках
763{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}
764в таблице {@link android.provider.ContactsContract.Data}).
765            Установив этот флаг в строке таблицы {@link android.provider.ContactsContract.Settings}
766для типа аккаунта и имени аккаунта, вы можете принудительно сделать видимыми контакты, не принадлежащие какой-либо группе.
767            Один из вариантов использования этого флага — отображение контактов с серверов, на которых не используются группы.
768        </td>
769    </tr>
770    <tr>
771        <td>
772            «1» — для этого аккаунта и аккаунтов этого типа контакты, не принадлежащие к группе,
773отображаются в интерфейсах пользователя приложений Android.
774        </td>
775
776    </tr>
777    <tr>
778        <td>{@link android.provider.ContactsContract.SyncState}</td>
779        <td>(все)</td>
780        <td>
781            Эта таблица используется для хранения метаданных для вашего адаптера синхронизации.
782        </td>
783        <td>
784            С помощью этой таблицы вы можете на постоянной основе хранить на устройстве сведения о состоянии синхронизации и другие связанные с
785синхронизацией данные.
786        </td>
787    </tr>
788</table>
789<h2 id="Access">Доступ к поставщику контактов</h2>
790<p>
791    В этом разделе рассматриваются инструкции по получению доступа к данным из поставщика контактов, в частности,
792следующие:
793</p>
794<ul>
795    <li>
796        запросы объектов;
797    </li>
798    <li>
799        пакетное изменение;
800    </li>
801    <li>
802        получение и изменение данных с помощью намерений;
803    </li>
804    <li>
805        целостность данных.
806    </li>
807</ul>
808<p>
809    Дополнительные сведения о внесении изменений с помощью адаптеров синхронизации представлены в разделе
810<a href="#SyncAdapters">Адаптеры синхронизации поставщика контактов</a>.
811</p>
812<h3 id="Entities">Запрос объектов</h3>
813<p>
814    Таблицы поставщика контактов имеют иерархическую структуру, поэтому зачастую полезно
815извлекать строку и все связанные с ней ее дочерние строки. Например, для отображения
816всей информации о пользователе вы, возможно, захотите извлечь все строки
817{@link android.provider.ContactsContract.RawContacts} для одной строки
818{@link android.provider.ContactsContract.Contacts} или все строки
819{@link android.provider.ContactsContract.CommonDataKinds.Email} для одной строки
820{@link android.provider.ContactsContract.RawContacts}. Чтобы упростить этот процесс, в поставщике контактов имеются
821<strong>объекты</strong>, которые выступают в роли соединителей базы данных между
822таблицами.
823</p>
824<p>
825    Объект представляет собой подобие таблицы, состоящей из выбранных столбцов родительской таблицы и ее дочерней таблицы.
826    При запросе объекта вы предоставляете проекцию и критерии поиска на основе доступных в
827объекте столбцов. В результате вы получаете объект {@link android.database.Cursor}, в котором
828содержится одна строка для каждой извлеченной строки дочерней таблицы. Например, если запросить объект
829{@link android.provider.ContactsContract.Contacts.Entity} для имени контакта и все строки
830{@link android.provider.ContactsContract.CommonDataKinds.Email} для всех необработанных контактов,
831соответствующих этому имени, вы получите объект {@link android.database.Cursor}, содержащий по одной строке
832для каждой строки {@link android.provider.ContactsContract.CommonDataKinds.Email}.
833</p>
834<p>
835    Использование объектов упрощает запросы. С помощью объекта можно извлечь сразу все данные для
836контакта или необработанного контакта, вместо того, чтобы сначала делать запрос к родительской таблице для получения
837идентификатора и последующего запроса к дочерней таблице с использованием полученного идентификатора. Кроме того, поставщик контактов обрабатывает запрос
838объекта за одну транзакцию, что гарантирует внутреннюю согласованность полученных
839данных.
840</p>
841<p class="note">
842    <strong>Примечание.</strong> Объект обычно содержит не все столбцы
843родительской и дочерней таблиц. Если вы попытаетесь изменить имя столбца, который отсутствует в списке
844констант имени столбца для объекта, вы получите {@link java.lang.Exception}.
845</p>
846<p>
847    Ниже представлен пример кода для получения всех строк необработанного контакта для контакта. Это фрагмент
848более крупного приложения, в котором имеются две операции: «основная» и «для получения сведений». Основная операция
849служит для получения списка строк контактов; при выборе пользователем контакта операция отправляет его идентификатор в операцию
850для получения сведений. Операция для получения сведений использует объект {@link android.provider.ContactsContract.Contacts.Entity}
851для отображения всех строк данных, полученных ото всех необработанных контактов, которые связаны с выбранным
852контактом.
853</p>
854<p>
855    Вот фрагмент кода операции «для получения сведений»:
856</p>
857<pre>
858...
859    /*
860     * Appends the entity path to the URI. In the case of the Contacts Provider, the
861     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
862     */
863    mContactUri = Uri.withAppendedPath(
864            mContactUri,
865            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);
866
867    // Initializes the loader identified by LOADER_ID.
868    getLoaderManager().initLoader(
869            LOADER_ID,  // The identifier of the loader to initialize
870            null,       // Arguments for the loader (in this case, none)
871            this);      // The context of the activity
872
873    // Creates a new cursor adapter to attach to the list view
874    mCursorAdapter = new SimpleCursorAdapter(
875            this,                        // the context of the activity
876            R.layout.detail_list_item,   // the view item containing the detail widgets
877            mCursor,                     // the backing cursor
878            mFromColumns,                // the columns in the cursor that provide the data
879            mToViews,                    // the views in the view item that display the data
880            0);                          // flags
881
882    // Sets the ListView's backing adapter.
883    mRawContactList.setAdapter(mCursorAdapter);
884...
885&#64;Override
886public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
887
888    /*
889     * Sets the columns to retrieve.
890     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
891     * DATA1 contains the first column in the data row (usually the most important one).
892     * MIMETYPE indicates the type of data in the data row.
893     */
894    String[] projection =
895        {
896            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
897            ContactsContract.Contacts.Entity.DATA1,
898            ContactsContract.Contacts.Entity.MIMETYPE
899        };
900
901    /*
902     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
903     * contact collated together.
904     */
905    String sortOrder =
906            ContactsContract.Contacts.Entity.RAW_CONTACT_ID +
907            " ASC";
908
909    /*
910     * Returns a new CursorLoader. The arguments are similar to
911     * ContentResolver.query(), except for the Context argument, which supplies the location of
912     * the ContentResolver to use.
913     */
914    return new CursorLoader(
915            getApplicationContext(),  // The activity's context
916            mContactUri,              // The entity content URI for a single contact
917            projection,               // The columns to retrieve
918            null,                     // Retrieve all the raw contacts and their data rows.
919            null,                     //
920            sortOrder);               // Sort by the raw contact ID.
921}
922</pre>
923<p>
924    По завершении загрузки {@link android.app.LoaderManager} выполняет обратный вызов метода
925{@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D)
926onLoadFinished()}. Одним их входящих аргументов для этого метода является
927{@link android.database.Cursor} с результатом запроса. В своем приложении вы можете
928получить данные из этого объекта {@link android.database.Cursor} для его отображения или дальнейшей работы с ним.
929</p>
930<h3 id="Transactions">Пакетное изменение</h3>
931<p>
932    При каждой возможности данные в поставщике контактов следует вставлять, обновлять и удалять в
933«пакетном режиме» путем создания {@link java.util.ArrayList} из объектов
934{@link android.content.ContentProviderOperation} и вызова метода
935{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Поскольку
936поставщик контактов выполняет все операции в методе
937{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} за одну
938транзакцию, ваши изменения всегда будут находиться в рамках репозитория контактов и
939всегда будут согласованными. Пакетное изменение также упрощает вставку необработанного контакта одновременно с его подробными
940данными.
941</p>
942<p class="note">
943    <strong>Примечание.</strong> Чтобы изменить <em>отдельный</em> необработанный контакт, рекомендуется отправить намерение в
944приложение для работы с контактами на устройстве вместо обработки изменения в вашем приложении.
945Более подробно эта операция описана в разделе
946<a href="#Intents">Получение и изменение данных с помощью намерений</a>.
947</p>
948<h4>Пределы</h4>
949<p>
950    Пакетное изменение большого количества операций может заблокировать выполнение других процессов,
951что может негативно сказаться на работе пользователя с приложением. Чтобы упорядочить все необходимые изменения
952в рамках как можно меньшего количества отдельных списков и при этом предотвратить
953блокирование работы системы, следует задать <strong>пределы</strong> для одной или нескольких операций.
954    Предел представляет собой объект {@link android.content.ContentProviderOperation}, в качестве значения параметра
955{@link android.content.ContentProviderOperation#isYieldAllowed()} которого задано
956<code>true</code>. При достижении поставщиком контактов предела он приостанавливает свою работу,
957чтобы могли выполняться другие процессы, и закрывает текущую транзакцию. Когда поставщик запускается снова, он
958выполняет следующую операцию в {@link java.util.ArrayList} и запускает
959новую транзакцию.
960</p>
961<p>
962    Использование пределов позволяет за один вызов метода
963{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} выполнять более одной транзакции. По этой причине
964вам следует задать предел для последней операции с набором связанных строк.
965    Например, необходимо задать предел для последней операции в наборе, которая
966добавляет строки необработанного контакта и связанные с ним строки данных, или для последней операции с набором строк, связанных
967с одним контактом.
968</p>
969<p>
970    Пределы также являются единицами атомарных операций. Все операции доступа в промежутке между двумя пределами завершаются либо
971успехом, либо сбоем в рамках одной единицы. Если любой из пределов не задан, наименьшей
972атомарной операцией считается весь пакет операций. Использование пределов позволяет предотвратить
973снижение производительности системы и одновременно обеспечить выполнение набора
974операций на атомарном уровне.
975</p>
976<h4>Изменение обратных ссылок</h4>
977<p>
978    При вставке новой строки необработанного контакта и связанных с ним рядов данных в виде набора объектов
979{@link android.content.ContentProviderOperation} вам приходится связывать строки данных
980со строкой необработанного контакта путем вставки значения
981{@code android.provider.BaseColumns#_ID} необработанного контакта в виде значения
982{@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Однако это значение
983недоступно, когда вы создаете{@link android.content.ContentProviderOperation}
984для строки данных, поскольку вы еще не применили
985{@link android.content.ContentProviderOperation} для строки необработанного контакта. Чтобы обойти это ограничение,
986в классе {@link android.content.ContentProviderOperation.Builder} предусмотрен метод
987{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}.
988    С помощью этого метода можно вставлять или изменять столбец
989с результатом предыдущей операции.
990</p>
991<p>
992    В методе {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
993предусмотрено два аргумента:
994</p>
995    <dl>
996        <dt>
997            <code>key</code>
998        </dt>
999        <dd>
1000            Ключ для пары «ключ-значение». Значением этого аргумента должно быть имя столбца
1001в таблице, которую вы изменяете.
1002        </dd>
1003        <dt>
1004            <code>previousResult</code>
1005        </dt>
1006        <dd>
1007            Индекс значения, начинающийся с «0», в массиве объектов
1008{@link android.content.ContentProviderResult} из метода
1009{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. По мере
1010выполнения пакетных операций результат каждой операции сохраняется в
1011промежуточном массиве результатов. Значением <code>previousResult</code> является индекс
1012одного из этих результатов, который извлекается и хранится со значением
1013<code>key</code>. Благодаря этому можно вставить новую запись необработанного контакта и получить обратно его значение
1014{@code android.provider.BaseColumns#_ID}, а затем создать «обратную ссылку» на
1015значение при добавлении строки {@link android.provider.ContactsContract.Data}.
1016            <p>
1017                Целиком весь результат создается при первом вызове метода
1018{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}.
1019Размер результата равен размеру {@link java.util.ArrayList} предоставленных вами объектов
1020{@link android.content.ContentProviderOperation}. Однако для всех
1021элементов в массиве результатов присваивается значение <code>null</code>, и при попытке
1022воспользоваться обратной ссылкой на результат еще не выполненной операции метод
1023{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
1024выдает {@link java.lang.Exception}.
1025
1026            </p>
1027        </dd>
1028    </dl>
1029<p>
1030    Ниже представлены фрагменты кода для вставки нового необработанного контакта и его данных в пакетном режиме. Они включают
1031код, который задает предел и использует обратную ссылку. Эти фрагменты
1032представляют собой расширенную версию метода <code>createContacEntry()</code>, который входит в класс
1033<code>ContactAdder</code> в примере приложения
1034<code><a href="{@docRoot}resources/samples/ContactManager/index.html">
1035    Contact Manager</a></code>.
1036</p>
1037<p>
1038    Первый фрагмент кода служит для извлечения данных контакта из пользовательского интерфейса. На этом этапе пользователь уже выбрал
1039аккаунт, для которого необходимо добавить новый необработанный контакт.
1040</p>
1041<pre>
1042// Creates a contact entry from the current UI values, using the currently-selected account.
1043protected void createContactEntry() {
1044    /*
1045     * Gets values from the UI
1046     */
1047    String name = mContactNameEditText.getText().toString();
1048    String phone = mContactPhoneEditText.getText().toString();
1049    String email = mContactEmailEditText.getText().toString();
1050
1051    int phoneType = mContactPhoneTypes.get(
1052            mContactPhoneTypeSpinner.getSelectedItemPosition());
1053
1054    int emailType = mContactEmailTypes.get(
1055            mContactEmailTypeSpinner.getSelectedItemPosition());
1056</pre>
1057<p>
1058    В следующем фрагменте кода создается операция для вставки строки необработанного контакта в таблицу
1059{@link android.provider.ContactsContract.RawContacts}:
1060</p>
1061<pre>
1062    /*
1063     * Prepares the batch operation for inserting a new raw contact and its data. Even if
1064     * the Contacts Provider does not have any data for this person, you can't add a Contact,
1065     * only a raw contact. The Contacts Provider will then add a Contact automatically.
1066     */
1067
1068     // Creates a new array of ContentProviderOperation objects.
1069    ArrayList&lt;ContentProviderOperation&gt; ops =
1070            new ArrayList&lt;ContentProviderOperation&gt;();
1071
1072    /*
1073     * Creates a new raw contact with its account type (server type) and account name
1074     * (user's account). Remember that the display name is not stored in this row, but in a
1075     * StructuredName data row. No other data is required.
1076     */
1077    ContentProviderOperation.Builder op =
1078            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
1079            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType())
1080            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());
1081
1082    // Builds the operation and adds it to the array of operations
1083    ops.add(op.build());
1084</pre>
1085<p>
1086    Затем код создает строки данных для строк отображаемого имени, телефона и адреса эл. почты.
1087</p>
1088<p>
1089    Каждый объект компонента операции использует метод
1090{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
1091для получения
1092{@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Ссылка возвращается
1093обратно к объекту {@link android.content.ContentProviderResult} из первой операции,
1094в результате чего добавляется строка необработанного контакта и возвращается его новое значение
1095{@code android.provider.BaseColumns#_ID}. После этого каждая строка данных автоматически связывается по своему
1096{@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}
1097с новой строкой {@link android.provider.ContactsContract.RawContacts}, которой она принадлежит.
1098</p>
1099<p>
1100    Объект {@link android.content.ContentProviderOperation.Builder}, который добавляет строку адреса эл. почты,
1101помечается флагом с помощью метода {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean)
1102withYieldAllowed()}, который задает предел:
1103</p>
1104<pre>
1105    // Creates the display name for the new raw contact, as a StructuredName data row.
1106    op =
1107            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
1108            /*
1109             * withValueBackReference sets the value of the first argument to the value of
1110             * the ContentProviderResult indexed by the second argument. In this particular
1111             * call, the raw contact ID column of the StructuredName data row is set to the
1112             * value of the result returned by the first operation, which is the one that
1113             * actually adds the raw contact row.
1114             */
1115            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
1116
1117            // Sets the data row's MIME type to StructuredName
1118            .withValue(ContactsContract.Data.MIMETYPE,
1119                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
1120
1121            // Sets the data row's display name to the name in the UI.
1122            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
1123
1124    // Builds the operation and adds it to the array of operations
1125    ops.add(op.build());
1126
1127    // Inserts the specified phone number and type as a Phone data row
1128    op =
1129            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
1130            /*
1131             * Sets the value of the raw contact id column to the new raw contact ID returned
1132             * by the first operation in the batch.
1133             */
1134            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
1135
1136            // Sets the data row's MIME type to Phone
1137            .withValue(ContactsContract.Data.MIMETYPE,
1138                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
1139
1140            // Sets the phone number and type
1141            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
1142            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType);
1143
1144    // Builds the operation and adds it to the array of operations
1145    ops.add(op.build());
1146
1147    // Inserts the specified email and type as a Phone data row
1148    op =
1149            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
1150            /*
1151             * Sets the value of the raw contact id column to the new raw contact ID returned
1152             * by the first operation in the batch.
1153             */
1154            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
1155
1156            // Sets the data row's MIME type to Email
1157            .withValue(ContactsContract.Data.MIMETYPE,
1158                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
1159
1160            // Sets the email address and type
1161            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
1162            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType);
1163
1164    /*
1165     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
1166     * will yield priority to other threads. Use after every set of operations that affect a
1167     * single contact, to avoid degrading performance.
1168     */
1169    op.withYieldAllowed(true);
1170
1171    // Builds the operation and adds it to the array of operations
1172    ops.add(op.build());
1173</pre>
1174<p>
1175    В последнем фрагменте кода представлен вызов метода
1176{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}
1177для вставки нового необработанного контакта и его строк данных.
1178</p>
1179<pre>
1180    // Ask the Contacts Provider to create a new contact
1181    Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" +
1182            mSelectedAccount.getType() + ")");
1183    Log.d(TAG,"Creating contact: " + name);
1184
1185    /*
1186     * Applies the array of ContentProviderOperation objects in batch. The results are
1187     * discarded.
1188     */
1189    try {
1190
1191            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
1192    } catch (Exception e) {
1193
1194            // Display a warning
1195            Context ctx = getApplicationContext();
1196
1197            CharSequence txt = getString(R.string.contactCreationFailure);
1198            int duration = Toast.LENGTH_SHORT;
1199            Toast toast = Toast.makeText(ctx, txt, duration);
1200            toast.show();
1201
1202            // Log exception
1203            Log.e(TAG, "Exception encountered while inserting contact: " + e);
1204    }
1205}
1206</pre>
1207<p>
1208    С помощью пакетных операций можно также реализовать<strong>оптимистическое управление параллелизмом</strong>.
1209Это метод применения транзакций изменения без необходимости блокировать базовый репозиторий.
1210    Чтобы воспользоваться этим методом, необходимо применить транзакцию и проверить наличие других изменений,
1211которые могли быть внесены в это же время. Если обнаружится, что имеется несогласованное изменение,
1212транзакцию можно откатить и выполнить повторно.
1213</p>
1214<p>
1215    Оптимистическое управление параллелизмом подходит для мобильных устройств, где с системой одновременно взаимодействует только один пользователь,
1216 а одновременный доступ к репозиторию данных нескольких пользователей — довольно редкое явление. Поскольку не применяется блокировка,
1217экономится ценное время, которое требуется на установку блокировок или ожидания того, когда другие транзакции отменят свои блокировки.
1218</p>
1219<p>
1220    Ниже представлен порядок использования оптимистического управления параллелизмом при обновлении одной строки
1221{@link android.provider.ContactsContract.RawContacts}.
1222</p>
1223<ol>
1224    <li>
1225        Извлеките столбец {@link android.provider.ContactsContract.SyncColumns#VERSION}
1226необработанного контакта, а также другие данные, которые необходимо извлечь.
1227    </li>
1228    <li>
1229        Создайте объект {@link android.content.ContentProviderOperation.Builder}, подходящий для
1230применения ограничения, с помощью метода
1231{@link android.content.ContentProviderOperation#newAssertQuery(Uri)}. Для URI контента
1232используйте {@link android.provider.ContactsContract.RawContacts#CONTENT_URI
1233RawContacts.CONTENT_URI},
1234добавив к нему {@code android.provider.BaseColumns#_ID} необработанного контакта.
1235    </li>
1236    <li>
1237        Для объекта {@link android.content.ContentProviderOperation.Builder} вызовите метод
1238{@link android.content.ContentProviderOperation.Builder#withValue(String, Object)
1239withValue()}, чтобы сравнить столбец {@link android.provider.ContactsContract.SyncColumns#VERSION}
1240с номером версии, которую вы только что получили.
1241    </li>
1242    <li>
1243        Для того же объекта {@link android.content.ContentProviderOperation.Builder} вызовите метод
1244{@link android.content.ContentProviderOperation.Builder#withExpectedCount(int)
1245withExpectedCount()}, чтобы убедиться в том, что проверочное утверждение проверяет только одну строка.
1246    </li>
1247    <li>
1248        Вызовите метод {@link android.content.ContentProviderOperation.Builder#build()}, чтобы создать объект
1249{@link android.content.ContentProviderOperation}, затем добавьте этот объект в качестве первого объекта в
1250{@link java.util.ArrayList}, который вы передаете в метод
1251{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}.
1252    </li>
1253    <li>
1254        Примените пакетную транзакцию.
1255    </li>
1256</ol>
1257<p>
1258    Если в промежутке между считыванием строки и попыткой ее изменения строка необработанного контакта была обновлена другой
1259операцией, assert {@link android.content.ContentProviderOperation}
1260завершится сбоем и в выполнении всего пакета операций будет отказано. Можно выбрать повторное выполнение
1261пакета или выполнить другое действие.
1262</p>
1263<p>
1264    В примере кода ниже демонстрируется, как создать assert
1265{@link android.content.ContentProviderOperation} после запроса одного необработанного контакта с помощью
1266{@link android.content.CursorLoader}.
1267</p>
1268<pre>
1269/*
1270 * The application uses CursorLoader to query the raw contacts table. The system calls this method
1271 * when the load is finished.
1272 */
1273public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
1274
1275    // Gets the raw contact's _ID and VERSION values
1276    mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
1277    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION));
1278}
1279
1280...
1281
1282// Sets up a Uri for the assert operation
1283Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID);
1284
1285// Creates a builder for the assert operation
1286ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri);
1287
1288// Adds the assertions to the assert operation: checks the version and count of rows tested
1289assertOp.withValue(SyncColumns.VERSION, mVersion);
1290assertOp.withExpectedCount(1);
1291
1292// Creates an ArrayList to hold the ContentProviderOperation objects
1293ArrayList ops = new ArrayList&lt;ContentProviderOperationg&gt;;
1294
1295ops.add(assertOp.build());
1296
1297// You would add the rest of your batch operations to "ops" here
1298
1299...
1300
1301// Applies the batch. If the assert fails, an Exception is thrown
1302try
1303    {
1304        ContentProviderResult[] results =
1305                getContentResolver().applyBatch(AUTHORITY, ops);
1306
1307    } catch (OperationApplicationException e) {
1308
1309        // Actions you want to take if the assert operation fails go here
1310    }
1311</pre>
1312<h3 id="Intents">Получение и изменение данных с помощью намерений</h3>
1313<p>
1314    С помощью отправки намерения в приложение для работы с контактами, которое имеется на устройстве, можно в обход получить доступ
1315к поставщику контактов. Намерение запускает пользовательский интерфейс приложения на устройстве, посредством которого пользователь
1316может работать с контактами. Такой тип доступа позволяет пользователю выполнять следующие действия:
1317    <ul>
1318        <li>выбор контактов из списка и их возврат в приложение для дальнейшей работы;</li>
1319        <li>изменение данных существующего контакта;</li>
1320        <li>вставка нового необработанного контакта для любых других аккаунтов;</li>
1321        <li>удаление контакта или его данных.</li>
1322    </ul>
1323<p>
1324    Если пользователь вставляет или обновляет данные , вы можете сначала собрать эти данные, а затем отправить их вместе
1325с намерением.
1326</p>
1327<p>
1328    При использовании намерений для доступа к поставщику контактов посредством приложения для работы с контактами, имеющегося на устройстве, вам
1329не нужно создавать собственный пользовательский интерфейс или код для доступа к поставщику. Также вам
1330не нужно запрашивать разрешение на чтение или запись в поставщик. Приложение для работы с контактами, имеющееся на устройстве, может
1331делегировать вам разрешение на чтение контакта, и поскольку вы вносите изменения
1332в поставщик через другое приложение, вам не нужно разрешение на запись.
1333</p>
1334<p>
1335    Более подробно общий процесс отправки намерения для получения доступа к поставщику описан в руководстве
1336<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Основные сведения о поставщике контента</a>
1337в разделе «Доступ к данным посредством намерений». В таблице 4 ниже представлены сводные сведения об операциях,
1338типе MIME и значениях данных, которые используются для доступных задач. Значения
1339дополнительных данных, которые можно использовать для
1340{@link android.content.Intent#putExtra(String, String) putExtra()}, указаны в справочной
1341документации по {@link android.provider.ContactsContract.Intents.Insert}.
1342</p>
1343<p class="table-caption" id="table4">
1344  <strong>Таблица 4.</strong> Намерения в поставщике контактов.
1345</p>
1346<table style="width:75%">
1347    <tr>
1348        <th scope="col" style="width:10%">Задача</th>
1349        <th scope="col" style="width:5%">Действие</th>
1350        <th scope="col" style="width:10%">Данные</th>
1351        <th scope="col" style="width:10%">Тип MIME</th>
1352        <th scope="col" style="width:25%">Примечания</th>
1353    </tr>
1354    <tr>
1355        <td><strong>Выбор контакта из списка</strong></td>
1356        <td>{@link android.content.Intent#ACTION_PICK}</td>
1357        <td>
1358            Одно из следующего:
1359            <ul>
1360                <li>
1361{@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI}
1362(отображение списка контактов);
1363                </li>
1364                <li>
1365{@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI}
1366(отображение номеров телефонов для необработанного контакта);
1367                </li>
1368                <li>
1369{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal#CONTENT_URI
1370StructuredPostal.CONTENT_URI}
1371(отображение списка почтовых адресов для необработанного контакта);
1372                </li>
1373                <li>
1374{@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI}
1375(отображение адресов эл. почты для необработанного контакта).
1376                </li>
1377            </ul>
1378        </td>
1379        <td>
1380            Не используется
1381        </td>
1382        <td>
1383            Отображение списка необработанных контактов или списка данных необработанного контакта (в зависимости от
1384предоставленного URI контента).
1385            <p>
1386                Вызовите метод
1387{@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()},
1388который возвращает URI контента для выбранной строки. URI представлен в форме
1389URI контента таблицы, к которому добавлен <code>LOOKUP_ID</code> строки.
1390                Приложение для работы с контактами, установленное на устройстве, делегирует этому URI контента
1391разрешения на чтение и запись, которые действуют в течение всего жизненного цикла вашей операции. Дополнительные сведения представлены в статье
1392<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Основные
1393сведения о поставщике контента</a>.
1394            </p>
1395        </td>
1396    </tr>
1397    <tr>
1398        <td><strong>Вставка нового необработанного контакта</strong></td>
1399        <td>{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION}</td>
1400        <td>Н/Д</td>
1401        <td>
1402            {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE
1403RawContacts.CONTENT_TYPE}, тип MIME для набора необработанных контактов.
1404        </td>
1405        <td>
1406            Отображение экрана <strong>Добавить контакт</strong> в приложении для работы с контактами, которое установлено на устройстве. Отображаются
1407значения дополнительных данных, добавленных вами в намерение. При отправке с помощью метода
1408{@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()}
1409URI контента нового добавленного необработанного контакта передается обратно в метод обратного вызова
1410{@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}
1411вашей операции в аргументе {@link android.content.Intent} в поле
1412data. Чтобы получить значение, вызовите метод {@link android.content.Intent#getData()}.
1413        </td>
1414    </tr>
1415    <tr>
1416        <td><strong>Изменение контакта</strong></td>
1417        <td>{@link android.content.Intent#ACTION_EDIT}</td>
1418        <td>
1419            {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
1420контакта. Операция редактора разрешит пользователю изменить любые данные, связанные с
1421этим контактом.
1422        </td>
1423        <td>
1424            {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
1425Contacts.CONTENT_ITEM_TYPE}, один контакт.</td>
1426        <td>
1427            Отображение экрана редактирования контакта в приложении для работы с контактами. Отображаются
1428значения дополнительных данных, добавленных вами в намерение. Когда пользователь нажимает на кнопку <strong>Готово</strong> для сохранения
1429внесенных изменений, ваша операция возвращается на передний план.
1430        </td>
1431    </tr>
1432    <tr>
1433        <td><strong>Отображение средства выбора, в котором также можно добавлять данные</strong></td>
1434        <td>{@link android.content.Intent#ACTION_INSERT_OR_EDIT}</td>
1435        <td>
1436            Н/Д
1437        </td>
1438        <td>
1439            {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE}
1440        </td>
1441         <td>
1442            Это намерение также отображает экран средства выбора приложения для работы с контактами. Пользователь
1443может выбрать контакт для изменения или добавить новый контакт. В зависимости от выбора отображается экран редактирования или добавления контакта,
1444и отображаются дополнительные данные,
1445переданные вами в намерение. Если ваше приложение отображает такие данные контакта, как адрес эл. почты или номер телефона,
1446воспользуйтесь этим намерением, чтобы разрешить пользователю добавлять данные к существующему
1447контакту.
1448            <p class="note">
1449                <strong>Примечание.</strong> Вам не нужно отправлять значение имени в дополнительные данные этого намерения,
1450поскольку пользователь всегда выбирает существующее имя или добавляет новое. Кроме того,
1451если отправить имя, а пользователь решит внести изменения, приложение для работы с контактами
1452отобразит отправленное вами имя, перезаписав предыдущее значение. Если пользователь
1453не заметит этого и сохранит изменения, старое значение будет утеряно.
1454            </p>
1455         </td>
1456    </tr>
1457</table>
1458<p>
1459    Приложение для работы с контактами, имеющееся на устройстве, не разрешает вам удалять необработанные контакты или любые его данные с
1460помощью намерений. Вместо этого для обработки необработанного контакта используйте метод
1461{@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()}
1462или {@link android.content.ContentProviderOperation#newDelete(Uri)
1463ContentProviderOperation.newDelete()}.
1464</p>
1465<p>
1466    Ниже представлен фрагмент кода для создания и отправки намерения, который вставляет новый
1467необработанный контакт и его данные.
1468</p>
1469<pre>
1470// Gets values from the UI
1471String name = mContactNameEditText.getText().toString();
1472String phone = mContactPhoneEditText.getText().toString();
1473String email = mContactEmailEditText.getText().toString();
1474
1475String company = mCompanyName.getText().toString();
1476String jobtitle = mJobTitle.getText().toString();
1477
1478// Creates a new intent for sending to the device's contacts application
1479Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION);
1480
1481// Sets the MIME type to the one expected by the insertion activity
1482insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
1483
1484// Sets the new contact name
1485insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);
1486
1487// Sets the new company and job title
1488insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company);
1489insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle);
1490
1491/*
1492 * Demonstrates adding data rows as an array list associated with the DATA key
1493 */
1494
1495// Defines an array list to contain the ContentValues objects for each row
1496ArrayList&lt;ContentValues&gt; contactData = new ArrayList&lt;ContentValues&gt;();
1497
1498
1499/*
1500 * Defines the raw contact row
1501 */
1502
1503// Sets up the row as a ContentValues object
1504ContentValues rawContactRow = new ContentValues();
1505
1506// Adds the account type and name to the row
1507rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType());
1508rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());
1509
1510// Adds the row to the array
1511contactData.add(rawContactRow);
1512
1513/*
1514 * Sets up the phone number data row
1515 */
1516
1517// Sets up the row as a ContentValues object
1518ContentValues phoneRow = new ContentValues();
1519
1520// Specifies the MIME type for this data row (all data rows must be marked by their type)
1521phoneRow.put(
1522        ContactsContract.Data.MIMETYPE,
1523        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
1524);
1525
1526// Adds the phone number and its type to the row
1527phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
1528
1529// Adds the row to the array
1530contactData.add(phoneRow);
1531
1532/*
1533 * Sets up the email data row
1534 */
1535
1536// Sets up the row as a ContentValues object
1537ContentValues emailRow = new ContentValues();
1538
1539// Specifies the MIME type for this data row (all data rows must be marked by their type)
1540emailRow.put(
1541        ContactsContract.Data.MIMETYPE,
1542        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
1543);
1544
1545// Adds the email address and its type to the row
1546emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);
1547
1548// Adds the row to the array
1549contactData.add(emailRow);
1550
1551/*
1552 * Adds the array to the intent's extras. It must be a parcelable object in order to
1553 * travel between processes. The device's contacts app expects its key to be
1554 * Intents.Insert.DATA
1555 */
1556insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);
1557
1558// Send out the intent to start the device's contacts app in its add contact activity.
1559startActivity(insertIntent);
1560</pre>
1561<h3 id="DataIntegrity">Целостность данных</h3>
1562<p>
1563    Поскольку в репозитории контактов содержится важная и конфиденциальная информация, которая, как ожидает пользователь, верна и
1564актуальна, в поставщике контактов предусмотрены четко определенные правила для обеспечения целостности данных. При изменении данных контактов вы обязаны
1565соблюдать эти правила. Вот наиболее
1566важные из этих правил:
1567</p>
1568<dl>
1569    <dt>
1570        Всегда добавляйте строку {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}
1571к каждой добавляемой вами строке {@link android.provider.ContactsContract.RawContacts}.
1572    </dt>
1573    <dd>
1574        Если в таблице {@link android.provider.ContactsContract.Data} имеется строка {@link android.provider.ContactsContract.RawContacts}
1575без строки {@link android.provider.ContactsContract.CommonDataKinds.StructuredName},
1576то могут возникнуть
1577проблемы во время агрегирования.
1578    </dd>
1579    <dt>
1580        Всегда связывайте новые строки {@link android.provider.ContactsContract.Data} с их
1581родительскими строками {@link android.provider.ContactsContract.RawContacts}.
1582    </dt>
1583    <dd>
1584        Строка {@link android.provider.ContactsContract.Data}, которая не связана
1585с {@link android.provider.ContactsContract.RawContacts}, не будет отображаться в
1586приложении для работы с контактами, имеющемся на устройстве, а также может привести к проблемам с адаптерами синхронизации.
1587    </dd>
1588    <dt>
1589        Следует изменять данные только тех необработанных контактов, которыми вы владеете.
1590    </dt>
1591    <dd>
1592        Помните о том, что поставщик контактов обычно управляет данными из
1593нескольких аккаунтов различных типов или служб в Интернете. Необходимо убедиться в том, что ваше приложение изменяет
1594или удаляет данные только для тех строк, которые принадлежат вам, а также в том, что оно вставляет данные с использованием только тех типов и имени аккаунта,
1595которыми вы управляете.
1596    </dd>
1597    <dt>
1598        Всегда используйте
1599для центров, URI контента, путей URI, имен столбцов, типов MIME и значений
1600{@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE} только те константы, которые определены в классе {@link android.provider.ContactsContract} и его подклассах.
1601    </dt>
1602    <dd>
1603        Это позволит избежать ошибок. Если какая либо константа устарела, компилятор сообщит об этом
1604с помощью соответствующего предупреждения.
1605    </dd>
1606</dl>
1607<h3 id="CustomData">Настраиваемые строки данных</h3>
1608<p>
1609    Создав и используя собственные типы MIME, вы можете вставлять, изменять, удалять и извлекать
1610в таблице{@link android.provider.ContactsContract.Data} собственные строки данных. Ваши строки
1611ограничены использованием столбца, который определен в
1612{@link android.provider.ContactsContract.DataColumns}, однако вы можете сопоставить ваши собственные имена столбцов по типам строк
1613с именами столбцов по умолчанию. Данные для ваших строк отображаются в приложении для работы с контактами, которое имеется на устройстве,
1614однако их не удастся изменить или удалить, а также пользователи не смогут
1615добавить дополнительные данные. Чтобы разрешить пользователям изменять ваши настраиваемые строки данных, необходимо реализовать в вашем приложении операцию
1616редактора.
1617</p>
1618<p>
1619    Для отображения настраиваемых данных укажите файл <code>contacts.xml</code>, содержащий элемент
1620<code>&lt;ContactsAccountType&gt;</code> и один или несколько его
1621<code>&lt;ContactsDataKind&gt;</code> дочерних элементов. Дополнительные сведения об этом представлены в разделе
1622<a href="#SocialStreamDataKind"><code>&lt;ContactsDataKind&gt; element</code></a>.
1623</p>
1624<p>
1625    Дополнительные сведения о настраиваемых типах MIME представлены в руководстве
1626<a href="{@docRoot}guide/topics/providers/content-provider-creating.html">Создание
1627поставщика контента</a>.
1628</p>
1629<h2 id="SyncAdapters">Адаптеры синхронизации поставщика контактов</h2>
1630<p>
1631    Поставщик контактов разработан специально для обработки операций <strong>синхронизации</strong>
1632данных контактов между устройством и службой в Интернете. Благодаря этому пользователи
1633могут загружать существующие данные на новое устройство и отправлять их в новый аккаунт.
1634    Синхронизация также обеспечивает предоставление пользователю всегда актуальных сведений, независимо от
1635источника их добавления и внесенных в них изменений. Еще одно преимущество синхронизации заключается в том,
1636что данные контактов доступны даже в том случае, если устройство не подключено к сети.
1637</p>
1638<p>
1639    Несмотря на множество различных способов реализации синхронизации данных, в системе Android имеется
1640подключаемая платформа синхронизации, которая позволяет автоматизировать выполнение следующих задач:
1641    <ul>
1642
1643    <li>
1644        проверка доступности сети;
1645    </li>
1646    <li>
1647        планирование и выполнение синхронизации на основе предпочтений пользователя;
1648    </li>
1649    <li>
1650        перезапуск остановленных процессов синхронизации.
1651    </li>
1652    </ul>
1653<p>
1654    Для использования этой платформы вы предоставляете подключаемый модуль адаптера синхронизации. Каждый адаптер синхронизации является уникальным
1655для службы и поставщика контента, однако способен работать с несколькими аккаунтами в одной службе. В платформе
1656также предусмотрена возможность использовать несколько адаптеров синхронизации для одной и той же службы или поставщика.
1657</p>
1658<h3 id="SyncClassesFiles">Классы и файлы адаптера синхронизации</h3>
1659<p>
1660    Адаптер синхронизации реализуется как подкласс класса
1661{@link android.content.AbstractThreadedSyncAdapter} и устанавливается в составе приложения
1662Android. Система узнает о наличии адаптера синхронизации из элементов в манифесте
1663вашего приложения, а также из особого файла XML, на который имеется указание в манифесте. В файле XML определяются
1664тип аккаунта в онлайн-службе и центр поставщика контента, которые вместе служат уникальными
1665идентификаторами адаптера. Адаптер синхронизации находится в неактивном состоянии до тех пор, пока пользователь не добавит
1666тип аккаунта и не включит синхронизацию
1667с поставщиком контента.  На этом этапе система вступает в управление адаптером
1668, при необходимости вызывая его для синхронизации данных между поставщиком контента и сервером.
1669</p>
1670<p class="note">
1671    <strong>Примечание.</strong> Использование типа аккаунта для идентификации адаптера синхронизации
1672позволяет системе обнаруживать и группировать адаптеры синхронизации, которые обращаются к разным службам
1673из одной и той же организации. Например, у всех адаптеров синхронизации для онлайн-служб Google
1674один и тот же тип аккаунта — <code>com.google</code>. Когда пользователи добавляют на свои устройства аккаунт Google, все
1675установленные адаптеры синхронизации группируются вместе; каждый из адаптеров
1676синхронизируется только с отдельным поставщиком контента на устройстве.
1677</p>
1678<p>
1679    Поскольку в большинстве служб пользователям сначала необходимо подтвердить свою подлинность, прежде чем они смогут получить доступ к данным,
1680система Android предлагает платформу аутентификации, которая аналогична
1681платформе адаптера синхронизации и зачастую используется совместно с ней. Платформа аутентификации
1682использует подключаемые структуры проверки подлинности, которые представляют собой подклассы класса
1683{@link android.accounts.AbstractAccountAuthenticator}. Такая структура проверяет
1684подлинность пользователя следующим образом:
1685    <ol>
1686        <li>
1687            Сначала собираются сведения об имени пользователя и его пароле или аналогичная информация (<strong>учетные данные</strong>
1688пользователя).
1689        </li>
1690        <li>
1691            Затем учетные данные оправляются в службу.
1692        </li>
1693        <li>
1694            Наконец, изучается ответ, полученный от службы.
1695        </li>
1696    </ol>
1697<p>
1698    Если служба приняла учетные данные, структура проверки подлинности может
1699сохранить их для использования в дальнейшем. Благодаря использованию структур проверки подлинности
1700{@link android.accounts.AccountManager} может предоставить доступ к любым маркерам аутентификации, которые
1701поддерживает структура проверки подлинности и которые она решает предоставить, например, к маркерам аутентификации OAuth2.
1702</p>
1703<p>
1704    Несмотря на то что аутентификация не требуется, она используется большинством служб для работы с контактами.
1705    Тем не менее, вам не обязательно использовать платформу аутентификации Android для проверки подлинности.
1706</p>
1707<h3 id="SyncAdapterImplementing">Реализация адаптера синхронизации</h3>
1708<p>
1709    Чтобы реализовать адаптер синхронизации для поставщика контактов, начните с создания
1710приложения Android, которое содержит следующие компоненты.
1711</p>
1712    <dl>
1713        <dt>
1714            Компонент {@link android.app.Service}, который отвечает на запросы системы
1715для привязки к адаптеру синхронизации.
1716        </dt>
1717        <dd>
1718            Когда системе требуется запустить синхронизацию, она вызывает метод
1719{@link android.app.Service#onBind(Intent) onBind()} службы, чтобы получить объект
1720{@link android.os.IBinder} для адаптера синхронизации. Благодаря этому система
1721может вызывать методы адаптера между процессами.
1722            <p>
1723                В
1724<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">примере адаптера синхронизации</a> именем класса этой службы является
1725<code>com.example.android.samplesync.syncadapter.SyncService</code>.
1726            </p>
1727        </dd>
1728        <dt>
1729            Адаптер синхронизации, фактически реализованный как конкретный подкласс
1730класса {@link android.content.AbstractThreadedSyncAdapter}.
1731        </dt>
1732        <dd>
1733            Этот класс не подходит для загрузки данных с сервера, отправки данных
1734с устройства и разрешения конфликтов. Основную свою работу адаптер
1735выполняет в методе {@link android.content.AbstractThreadedSyncAdapter#onPerformSync(
1736Account, Bundle, String, ContentProviderClient, SyncResult)
1737onPerformSync()}. Этот класс допускает создание только одного экземпляра.
1738            <p>
1739                В
1740<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">примере адаптера синхронизации</a> адаптер определяется в классе
1741<code>com.example.android.samplesync.syncadapter.SyncAdapter</code>.
1742            </p>
1743        </dd>
1744        <dt>
1745            Подкласс класса {@link android.app.Application}.
1746        </dt>
1747        <dd>
1748            Этот класс выступает в роли фабрики для единственного экземпляра адаптера синхронизации. Воспользуйтесь методом
1749{@link android.app.Application#onCreate()}, чтобы создать экземпляр адаптера синхронизации, а затем
1750предоставьте статический метод get, чтобы возвратить единственный экземпляр в метод
1751{@link android.app.Service#onBind(Intent) onBind()} службы
1752адаптера синхронизации.
1753        </dd>
1754        <dt>
1755            <strong>Необязательно:</strong> компонент {@link android.app.Service}, который отвечает на запросы
1756системы для аутентификации пользователей.
1757        </dt>
1758        <dd>
1759            {@link android.accounts.AccountManager} запускает службу, чтобы начать процесс
1760аутентификации. Метод {@link android.app.Service#onCreate()} службы создает экземпляр
1761объекта структуры проверки подлинности. Когда системе требуется запустить аутентификацию аккаунта пользователя для
1762адаптера синхронизации приложения, она вызывает метод
1763{@link android.app.Service#onBind(Intent) onBind()} службы, чтобы получить объект
1764{@link android.os.IBinder} для структуры проверки подлинности. Благодаря этому система
1765может вызывать методы структуры проверки подлинности между процессами.
1766            <p>
1767                В
1768<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">примере адаптера синхронизации</a> именем класса этой службы является
1769<code>com.example.android.samplesync.authenticator.AuthenticationService</code>.
1770            </p>
1771        </dd>
1772        <dt>
1773            <strong>Необязательно:</strong> конкретный подкласс класса
1774{@link android.accounts.AbstractAccountAuthenticator}, который обрабатывает запросы на
1775аутентификацию.
1776        </dt>
1777        <dd>
1778            В этом классе имеются методы, которые {@link android.accounts.AccountManager} вызывает
1779для проверки подлинности учетных данных пользователя на сервере. Подробности процесса
1780аутентификации значительно различаются в зависимости от технологии, используемой на сервере. Чтобы узнать подробнее об аутентификации,
1781обратитесь к соответствующей документации к программному обеспечению используемого сервера.
1782            <p>
1783                В
1784<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">примере адаптера синхронизации</a> структура проверки подлинности определяется в классе
1785<code>com.example.android.samplesync.authenticator.Authenticator</code>.
1786            </p>
1787        </dd>
1788        <dt>
1789            Файлы XML, в которых определяются адаптер синхронизация и структура проверки подлинности для системы.
1790        </dt>
1791        <dd>
1792            Описанные ранее компоненты службы адаптера синхронизации и структуры проверки подлинности определяются
1793в элементах
1794<code>&lt;<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>&gt;</code>
1795в манифесте приложения. Эти элементы
1796включают дочерние элементы
1797<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
1798, в которых имеются определенные данные для
1799системы.
1800            <ul>
1801                <li>
1802                    Элемент
1803<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
1804для службы адаптера синхронизации указывает на файл
1805XML <code>res/xml/syncadapter.xml</code>. В свою очередь, в этом файле задается
1806URI веб-службы для синхронизации с поставщиком контактов,
1807а также тип аккаунта для этой веб-службы.
1808                </li>
1809                <li>
1810                    <strong>Необязательно:</strong> элемент
1811<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
1812для структуры проверки подлинности указывает на файл XML
1813<code>res/xml/authenticator.xml</code>. В свою очередь, в этом файле задается
1814тип аккаунта, который поддерживает структура проверки подлинности, а также ресурсы пользовательского интерфейса,
1815которые отображаются в процессе аутентификации. Тип аккаунта, указанный в этом
1816элементе, должен совпадать с типом аккаунта, который задан для
1817адаптера синхронизации.
1818                </li>
1819            </ul>
1820        </dd>
1821    </dl>
1822<h2 id="SocialStream">Потоки данных из социальных сетей</h2>
1823<p>
1824    Для управления входящими данными из социальных сетей используются таблицы {@code android.provider.ContactsContract.StreamItems}
1825и
1826{@code android.provider.ContactsContract.StreamItemPhotos}. Можно создать адаптер синхронизации, который добавляет поток данных
1827из вашей собственной сети в эти таблицы, либо вы можете считывать поток данных из этих таблиц и отображать
1828их в собственном приложении. Можно также реализовать оба этих способа. С помощью этих функций вы можете интегрировать службы социальных сетей
1829в компоненты Android для работы с социальными сетями.
1830</p>
1831<h3 id="StreamText">Текст из потока данных из социальных сетей</h3>
1832<p>
1833    Элементы потока всегда ассоциируются с необработанным контактом. Идентификатор
1834{@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} связывается со значением
1835<code>_ID</code> необработанного контакта. Тип аккаунта и его имя для необработанного
1836контакта также хранятся в строке элемента потока.
1837</p>
1838<p>
1839    Данные из потока следует хранить в следующих столбцах:
1840</p>
1841<dl>
1842    <dt>
1843        {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE}
1844    </dt>
1845    <dd>
1846        <strong>Обязательный.</strong> Тип аккаунта пользователя для необработанного контакта, связанного с
1847этим элементом потока. Не забудьте задать это значение при вставке элемента потока.
1848    </dd>
1849    <dt>
1850        {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME}
1851    </dt>
1852    <dd>
1853        <strong>Обязательный.</strong> Имя аккаунта пользователя для необработанного контакта, связанного с
1854этим элементом потока. Не забудьте задать это значение при вставке элемента потока.
1855    </dd>
1856    <dt>
1857        Столбцы идентификатора
1858    </dt>
1859    <dd>
1860        <strong>Обязательный.</strong> При вставке элемента потока необходимо вставить
1861указанные ниже столбцы идентификатора.
1862        <ul>
1863            <li>
1864                {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}: значение
1865{@code android.provider.BaseColumns#_ID} для контакта, с которым ассоциирован
1866этот элемент потока.
1867            </li>
1868            <li>
1869                {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}: значение
1870{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} для контакта, с которым ассоциирован
1871этот элемент потока.
1872            </li>
1873            <li>
1874                {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}: значение
1875{@code android.provider.BaseColumns#_ID} для необработанного контакта, с которым ассоциирован
1876этот элемент потока.
1877            </li>
1878        </ul>
1879    </dd>
1880    <dt>
1881        {@code android.provider.ContactsContract.StreamItemsColumns#COMMENTS}
1882    </dt>
1883    <dd>
1884        Необязательный. В нем хранится сводная информация, которую можно отобразить в начале элемента потока.
1885    </dd>
1886    <dt>
1887        {@code android.provider.ContactsContract.StreamItemsColumns#TEXT}
1888    </dt>
1889    <dd>
1890        Текст элемента потока: либо контент, опубликованный источником элемента,
1891либо описание некоторого действия, сгенерировавшего элемент потока. В этом столбце могут содержаться
1892любое форматирование и встроенные изображения ресурсов, рендеринг которых можно выполнить с помощью метода
1893{@link android.text.Html#fromHtml(String) fromHtml()}. Поставщик может обрезать слишком длинный контент
1894или заменить его часть многоточием, однако он попытается избежать нарушения тегов.
1895    </dd>
1896    <dt>
1897        {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP}
1898    </dt>
1899    <dd>
1900        Текстовая строка с информацией о времени вставки или обновления элемента в
1901<em>миллисекундах</em> от начала отсчета времени. Обслуживанием этого столбца занимаются приложения, которые вставляют или
1902обновляют элементы потока; поставщик контактов не выполняет
1903это автоматически.
1904    </dd>
1905</dl>
1906<p>
1907    Для отображения идентификационной информации для элементов потока воспользуйтесь
1908{@code android.provider.ContactsContract.StreamItemsColumns#RES_ICON},
1909{@code android.provider.ContactsContract.StreamItemsColumns#RES_LABEL} и
1910{@code android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} для связывания с ресурсами
1911в вашем приложении.
1912</p>
1913<p>
1914    В таблице {@code android.provider.ContactsContract.StreamItems} также имеются столбцы
1915{@code android.provider.ContactsContract.StreamItemsColumns#SYNC1}—{@code android.provider.ContactsContract.StreamItemsColumns#SYNC4},
1916которые предназначены исключительно для
1917адаптеров синхронизации.
1918</p>
1919<h3 id="StreamPhotos">Фотографии из потока данных из социальных сетей</h3>
1920<p>
1921   Фотографии, связанные с элементом потока, хранятся в таблице
1922{@code android.provider.ContactsContract.StreamItemPhotos}. Столбец
1923{@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID}
1924в этой таблице связан со столбцом {@code android.provider.BaseColumns#_ID}
1925в таблице {@code android.provider.ContactsContract.StreamItems}. Ссылки на фотографии хранятся в следующих столбцах
1926таблицы:
1927</p>
1928<dl>
1929    <dt>
1930        Столбец {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} (объект BLOB).
1931    </dt>
1932    <dd>
1933        Представление фотографии в двоичном формате и с измененным поставщиком размером для ее хранения и отображения.
1934        Этот столбец доступен для обеспечения обратной совместимости с предыдущими версиями поставщика
1935контактов, которые использовались для хранения фотографий. Однако в текущей версии
1936поставщика мы не рекомендуем использовать этот столбец для хранения фотографий. Вместо этого воспользуйтесь столбцом
1937{@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} или
1938{@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} (или обоими
1939столбцами, как описано далее) для хранения фотографий в файле. В этом
1940столбце теперь хранятся миниатюры фотографий, доступных для чтения.
1941    </dd>
1942    <dt>
1943        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID}
1944    </dt>
1945    <dd>
1946        Числовой идентификатор фотографии для необработанного контакта. Добавьте это значение к константе
1947{@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI},
1948чтобы получить URI контента для одного файла фотографии, а затем вызовите метод
1949{@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
1950openAssetFileDescriptor()}, чтобы получить средство обработки файла фотографии.
1951    </dd>
1952    <dt>
1953        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI}
1954    </dt>
1955    <dd>
1956        URI контента, указывающий на файл фотографии, для фотографии, которая представлена этой строкой.
1957        Вызовите метод {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
1958openAssetFileDescriptor()}, передав в него этот URI, чтобы получить средство обработки файла фотографии.
1959    </dd>
1960</dl>
1961<h3 id="SocialStreamTables">Использование таблиц из потока данных из социальных сетей</h3>
1962<p>
1963    Эти таблицы работают аналогично другим основным таблицам в поставщике контактов, за исключением указанных ниже моментов.
1964</p>
1965    <ul>
1966        <li>
1967            Для работы с этими таблицами требуются дополнительные разрешения на доступ. Для чтения данных из них вашему приложению
1968должно быть предоставлено разрешение {@code android.Manifest.permission#READ_SOCIAL_STREAM}. Для
1969изменения таблиц ваше приложение должно иметь разрешение
1970{@code android.Manifest.permission#WRITE_SOCIAL_STREAM}.
1971        </li>
1972        <li>
1973            Для таблицы {@code android.provider.ContactsContract.StreamItems} существует ограничение на количество строк,
1974которое можно хранить для каждого необработанного контакта. При достижении этого ограничения
1975поставщик контактов освобождает место для новых строк элементов потока путем автоматического удаления
1976строк со самой старой меткой
1977{@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP}. Чтобы получить это ограничение,
1978запросите URI контента
1979{@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI}. Для всех аргументов,
1980отличных от URI контента, можно оставить значение <code>null</code>. Запрос возвращает
1981объект Cursor, в котором содержится одна строка с одним столбцом
1982{@code android.provider.ContactsContract.StreamItems#MAX_ITEMS}.
1983        </li>
1984    </ul>
1985
1986<p>
1987    Класс {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} определяет
1988дочернюю таблицу объектов {@code android.provider.ContactsContract.StreamItemPhotos}, в которой содержатся
1989строки для одного элемента потока.
1990</p>
1991<h3 id="SocialStreamInteraction">Взаимодействие с потоками данных из социальных сетей</h3>
1992<p>
1993    Управление потоком данных из социальных сетей осуществляется поставщиком контактов совместно с приложением для управления контактами, имеющимся на устройстве.
1994Такой подход позволяет организовать эффективное использование данных из социальных сетей
1995с данными о существующих контактах. Доступны указанные ниже функции.
1996</p>
1997    <ul>
1998        <li>
1999            Организовав синхронизацию данных из социальной службы с поставщиком контактов посредством
2000адаптера синхронизации, вы можете получать данные о недавней активности контактов пользователя и хранить такие данные в таблицах
2001,{@code android.provider.ContactsContract.StreamItems}
2002и {@code android.provider.ContactsContract.StreamItemPhotos} для использования в дальнейшем.
2003        </li>
2004        <li>
2005            Помимо регулярной синхронизации, адаптер синхронизации можно настроить на получение
2006дополнительных данных при выборе пользователем контакта для просмотра. Благодаря этому ваш адаптер синхронизации
2007может получать фотографии высокого разрешения и самые актуальные элементы потока для контакта.
2008        </li>
2009        <li>
2010            Регистрируя уведомление в приложении для работы с контактами и в поставщике
2011контактов, вы можете<em>получать</em> намерения при просмотре контакта и обновлять на этом этапе
2012данные о состоянии контакта из вашей службы. Такой подход может обеспечить большее быстродействие и меньший объем
2013использования полосы пропускания, чем выполнение полной синхронизации с помощью адаптера синхронизации.
2014        </li>
2015        <li>
2016            Пользователи могут добавить контакт в вашу службу социальной сети, обратившись к контакту
2017в приложении для работы с контактами, которое имеется на устройстве. Это реализуется с помощью функции «пригласить контакт»,
2018для включения которой используется сочетание операции,
2019которая добавляет существующий контакт в вашу сеть, и файла XML, в котором представлены сведения о вашем приложении для поставщика контактов и приложения для работы с
2020контактами.
2021        </li>
2022    </ul>
2023<p>
2024    Регулярная синхронизация элементов потока с помощью поставщика контактов выполняется так же,
2025как и любая другая синхронизация. Дополнительные сведения о синхронизации представлены в разделе
2026<a href="#SyncAdapters">Адаптеры синхронизации поставщика контактов</a>. Регистрация уведомлений
2027и приглашение контактов рассматриваются в следующих двух разделах.
2028</p>
2029<h4>Регистрация для обработки просмотров контактов в социальных сетях</h4>
2030<p>
2031    Чтобы зарегистрировать адаптер синхронизации для получения уведомлений о просмотрах пользователями контакта,
2032управление которым осуществляется вашим адаптером синхронизации, выполните указанные ниже действия.
2033</p>
2034<ol>
2035    <li>
2036        В каталоге <code>res/xml/</code> своего проекта создайте файл
2037<code>contacts.xml</code>. Если у вас уже есть этот файл, переходите к следующему действию.
2038    </li>
2039    <li>
2040        В этом файле добавьте элемент
2041<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
2042        Если этот элемент уже существует, можете переходить к следующему действию.
2043    </li>
2044    <li>
2045        Чтобы зарегистрировать службу, которой отправляется уведомление при открытии пользователем страницы со сведениями о контакте
2046в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут
2047<code>viewContactNotifyService="<em>serviceclass</em>"</code> к элементу, где
2048<code><em>serviceclass</em></code> — это полное имя класса службы,
2049которая должна получить намерение из приложения для работы с контактами. Для службы-уведомителя
2050используйте класс, который является расширением класса {@link android.app.IntentService}, чтобы разрешить службе
2051получать намерения. Данные во входящем намерении содержат URI контента необработанного
2052контакта, выбранного пользователем. В службе-уведомителе можно привязать адаптер синхронизации, а затем вызвать его
2053для обновления данных для необработанного контакта.
2054    </li>
2055</ol>
2056<p>
2057    Чтобы зарегистрировать операцию, которую следует вызвать при выборе пользователем элемента потока или фотографии (или обоих элементов), выполните указанные ниже действия.
2058</p>
2059<ol>
2060    <li>
2061        В каталоге <code>res/xml/</code> своего проекта создайте файл
2062<code>contacts.xml</code>. Если у вас уже есть этот файл, переходите к следующему действию.
2063    </li>
2064    <li>
2065        В этом файле добавьте элемент
2066<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
2067        Если этот элемент уже существует, можете переходить к следующему действию.
2068    </li>
2069    <li>
2070        Чтобы зарегистрировать одну из ваших операций для обработки выбора пользователем элемента потока
2071в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут
2072<code>viewStreamItemActivity="<em>activityclass</em>"</code> к элементу, где
2073<code><em>activityclass</em></code> — это полное имя класса операции,
2074которая должна получить намерение из приложения для работы с контактами.
2075    </li>
2076    <li>
2077        Чтобы зарегистрировать одну из ваших операций для обработки выбора пользователем фотографии в потоке
2078в приложении для работы с контактами, которое имеется на устройстве, добавьте атрибут
2079<code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> к элементу, где
2080<code><em>activityclass</em></code> — это полное имя класса операции,
2081которая должна получить намерение из приложения для работы с контактами.
2082    </li>
2083</ol>
2084<p>
2085    Дополнительные сведения об элементе <code>&lt;ContactsAccountType&gt;</code> представлены в разделе
2086<a href="#SocialStreamAcctType">элемент &lt;ContactsAccountType&gt;</a>.
2087</p>
2088<p>
2089    Данные во входящем намерении содержат URI контента элемента или фотографии, выбранных пользователем.
2090    Чтобы использовать разные операции для текстовых элементов и фотографий, используйте оба атрибута в одном файле.
2091</p>
2092<h4>Взаимодействие со службой социальной сети</h4>
2093<p>
2094    Пользователям не обязательно выходить из приложения для работы с контактами, которое имеется на устройстве, чтобы пригласить контакт на сайт
2095социальной сети. Вместо этого приложение для работы с контактами может отправить намерение для приглашения
2096контакта в одну из ваших операций. Для этого выполните указанные ниже действия.
2097</p>
2098<ol>
2099    <li>
2100        В каталоге <code>res/xml/</code> своего проекта создайте файл
2101<code>contacts.xml</code>. Если у вас уже есть этот файл, переходите к следующему действию.
2102    </li>
2103    <li>
2104        В этом файле добавьте элемент
2105<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
2106        Если этот элемент уже существует, можете переходить к следующему действию.
2107    </li>
2108    <li>
2109        Добавьте следующие атрибуты:
2110        <ul>
2111            <li><code>inviteContactActivity="<em>activityclass</em>"</code>;</li>
2112            <li>
2113                <code>inviteContactActionLabel="&#64;string/<em>invite_action_label</em>"</code>.
2114            </li>
2115        </ul>
2116        Значение <code><em>activityclass</em></code> представляет собой полное имя класса операции,
2117которая должна получить намерение. Значение<code><em>invite_action_label</em></code>
2118— это текстовая строка, которая отображается в меню <strong>Добавить подключение</strong>
2119в приложении для работы с контактами.
2120    </li>
2121</ol>
2122<p class="note">
2123    <strong>Примечание.</strong> <code>ContactsSource</code> — это устаревшее имя тега для
2124<code>ContactsAccountType</code>, которое больше не используется.
2125</p>
2126<h3 id="ContactsFile">Ссылка contacts.xml</h3>
2127<p>
2128    В файле <code>contacts.xml</code> содержатся элементы XML, которые управляют взаимодействием вашего
2129адаптера синхронизации и вашего приложения с поставщиком контактов и приложением для работы с контактами. Эти
2130элементы описаны в следующих разделах.
2131</p>
2132<h4 id="SocialStreamAcctType">Элемент &lt;ContactsAccountType&gt;</h4>
2133<p>
2134    Элемент <code>&lt;ContactsAccountType&gt;</code> управляет взаимодействием вашего
2135приложения с приложением для работы с контактами. Ниже представлен его синтаксис.
2136</p>
2137<pre>
2138&lt;ContactsAccountType
2139        xmlns:android="http://schemas.android.com/apk/res/android"
2140        inviteContactActivity="<em>activity_name</em>"
2141        inviteContactActionLabel="<em>invite_command_text</em>"
2142        viewContactNotifyService="<em>view_notify_service</em>"
2143        viewGroupActivity="<em>group_view_activity</em>"
2144        viewGroupActionLabel="<em>group_action_text</em>"
2145        viewStreamItemActivity="<em>viewstream_activity_name</em>"
2146        viewStreamItemPhotoActivity="<em>viewphotostream_activity_name</em>"&gt;
2147</pre>
2148<p>
2149    <strong>находится в:</strong>
2150</p>
2151<p>
2152    <code>res/xml/contacts.xml</code>
2153</p>
2154<p>
2155    <strong>может содержать:</strong>
2156</p>
2157<p>
2158    <strong><code>&lt;ContactsDataKind&gt;</code></strong>
2159</p>
2160<p>
2161    <strong>Описание</strong>
2162</p>
2163<p>
2164    Этот элемент объявляет компоненты и элементы пользовательского интерфейса, с помощью которых пользователи могут приглашать свои контакты
2165в социальную сеть, уведомлять пользователей при обновлении одного из их потоков данных из социальных сетей и
2166др.
2167</p>
2168<p>
2169    Обратите внимание, что префикс атрибута <code>android:</code> необязательно использовать для атрибутов
2170<code>&lt;ContactsAccountType&gt;</code>.
2171</p>
2172<p>
2173    <strong>Атрибуты</strong>
2174</p>
2175<dl>
2176    <dt>{@code inviteContactActivity}</dt>
2177    <dd>
2178        Полное имя класса операции в вашем приложении, которую необходимо активировать
2179при выборе пользователем элемента <strong>Добавить подключение</strong> в приложении
2180для работы с контактами, которое имеется на устройстве.
2181    </dd>
2182    <dt>{@code inviteContactActionLabel}</dt>
2183    <dd>
2184        Текстовая строка, которая отображается для операции, заданной в
2185{@code inviteContactActivity}, в меню <strong>Добавить подключение</strong>.
2186        Например, можно указать фразу «Следите за новостями в моей сети». Для этого элемента можно использовать
2187идентификатор строкового ресурса.
2188    </dd>
2189    <dt>{@code viewContactNotifyService}</dt>
2190    <dd>
2191        Полное имя класса службы в вашем приложении, которая должна получать
2192уведомления при просмотре контакта пользователем. Такое уведомление отправляется приложением для работы с контактами,
2193которое имеется на устройстве; благодаря этому ваше приложение может отложить выполнение операций, требующих обработки большого объема данных, до тех пор
2194, пока это не потребуется. Например, ваше приложение может реагировать на такое уведомление
2195путем считывания и отображения фотографии контакта в высоком разрешении и самых актуальных
2196элементов потока данных из социальной сети. Дополнительные сведения об этой функции представлены в разделе
2197<a href="#SocialStreamInteraction">Взаимодействие с потоками данных из социальных сетей</a>. Пример
2198службы уведомлений представлен в файле
2199<code>NotifierService.java</code> в
2200образце приложения<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a>.
2201    </dd>
2202    <dt>{@code viewGroupActivity}</dt>
2203    <dd>
2204        Полное имя класса операции в вашем приложении, которая может отобразить
2205информацию о группе. При нажатии пользователем на метку группы в приложении для работы с данными,
2206которое имеется на устройстве, отображается пользовательский интерфейс для этой операции.
2207    </dd>
2208    <dt>{@code viewGroupActionLabel}</dt>
2209    <dd>
2210        Метка, отображаемая приложением для работы с контактами для элемента пользовательского интерфейса, с помощью которой
2211пользователь может просмотреть группы в вашем приложении.
2212        <p>
2213            Например, если вы установили приложение Google+ на ваше устройство и выполняете синхронизацию
2214данных в Google+ с приложением для работы с контактами, то круги Google+ будут обозначены в приложении для работы с контактами как
2215группы на вкладке <strong>Группы</strong>. При нажатии на на круг
2216Google+ участники крга отобразятся как группа контактов. В верхней части экрана
2217находится значок Google+; если нажать на него, управление перейдет в приложение
2218Google+. В приложении для управления контактами это реализовано с помощью
2219{@code viewGroupActivity}, в которой значок Google+ используется в качестве значения
2220{@code viewGroupActionLabel}.
2221        </p>
2222        <p>
2223            Для этого атрибута можно использовать идентификатор строкового ресурса.
2224        </p>
2225    </dd>
2226    <dt>{@code viewStreamItemActivity}</dt>
2227    <dd>
2228        Полное имя класса операции в вашем приложении, которую запускает
2229приложение для работы с контактами, когда пользователь выбирает элемент потока для необработанного контакта.
2230    </dd>
2231    <dt>{@code viewStreamItemPhotoActivity}</dt>
2232    <dd>
2233        Полное имя класса операции в вашем приложении, которую запускает
2234приложение для работы с контактами, когда пользователь выбирает фотографию в элементе
2235потока для необработанного контакта.
2236    </dd>
2237</dl>
2238<h4 id="SocialStreamDataKind">Элемент &lt;ContactsDataKind&gt;</h4>
2239<p>
2240    Элемент <code>&lt;ContactsDataKind&gt;</code> управляет отображением настраиваемых строк данных вашего
2241приложения в интерфейсе приложения для работы с контактами, которое имеется на устройстве. Ниже представлен его синтаксис.
2242</p>
2243<pre>
2244&lt;ContactsDataKind
2245        android:mimeType="<em>MIMEtype</em>"
2246        android:icon="<em>icon_resources</em>"
2247        android:summaryColumn="<em>column_name</em>"
2248        android:detailColumn="<em>column_name</em>"&gt;
2249</pre>
2250<p>
2251    <strong>находится в:</strong>
2252</p>
2253<code>&lt;ContactsAccountType&gt;</code>
2254<p>
2255    <strong>Описание</strong>
2256</p>
2257<p>
2258    Используйте этот элемент для отображения содержимого настраиваемой строки данных в приложении для работы с контактами как части
2259сведений о необработанном контакте. Каждый дочерний элемент <code>&lt;ContactsDataKind&gt;</code>
2260элемента <code>&lt;ContactsAccountType&gt;</code> представляет собой тип настраиваемой строки данных, который
2261адаптер синхронизации добавляет в таблицу {@link android.provider.ContactsContract.Data}. Для каждого используемого вами настраиваемого типа MIME необходимо добавить один элемент
2262<code>&lt;ContactsDataKind&gt;</code>. Вам не нужно добавлять элемент
2263, если у вас имеется настраиваемая строка данных, для которой не требуется отображать данные.
2264</p>
2265<p>
2266    <strong>Атрибуты</strong>
2267</p>
2268<dl>
2269    <dt>{@code android:mimeType}</dt>
2270    <dd>
2271        Определенные вами настраиваемые типы MIME для одного из ваших типов настраиваемых строк данных в таблице
2272{@link android.provider.ContactsContract.Data}. Например, значение
2273<code>vnd.android.cursor.item/vnd.example.locationstatus</code> может быть настраиваемым
2274типом MIME для строки данных, в которой находятся записи о последнем известном местоположении контакта.
2275    </dd>
2276    <dt>{@code android:icon}</dt>
2277    <dd>
2278        <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Графический ресурс </a>
2279Android,
2280который приложение для работы с контактами отображает рядом с вашими данными. Используйте его для обозначения того,
2281что эти данные получены из вашей службы.
2282    </dd>
2283    <dt>{@code android:summaryColumn}</dt>
2284    <dd>
2285        Имя столбца для первого из двух значений, полученных из строки данных. Значение
2286отображается в виде первой строки записи в этой строке данных. Первая строка
2287предназначена для использования в качестве сводных данных, однако она необязательна. См. также
2288<a href="#detailColumn">android:detailColumn</a>.
2289    </dd>
2290    <dt>{@code android:detailColumn}</dt>
2291    <dd>
2292        Имя столбца для второго из двух значений, полученных из строки данных. Значение
2293отображается в виде второй строки записи в этой строке данных. См. также
2294{@code android:summaryColumn}.
2295    </dd>
2296</dl>
2297<h2 id="AdditionalFeatures">Дополнительные возможности поставщика контактов</h2>
2298<p>
2299    Помимо основных функций, описанных разделах выше, в поставщике
2300контактов предусмотрены указанные ниже полезные функции для работы с данными контактов.
2301</p>
2302    <ul>
2303       <li>Группы контактов</li>
2304       <li>Функции работы с фотографиями</li>
2305    </ul>
2306<h3 id="Groups">Группы контактов</h3>
2307<p>
2308    Поставщик контактов может дополнительно отметить коллекции связанных контактов с данными о
2309<strong>группе</strong>. Если серверу, который связан с учетной записью пользователя,
2310требуется сохранить группы, адаптеру синхронизации для типа этого аккаунта следует передать
2311данные о группах из поставщика контактов на сервер. При добавлении пользователем нового контакта на сервер
2312и последующем помещении этого контакта в новую группу адаптер синхронизации должен добавить эту новую группу в таблицу
2313{@link android.provider.ContactsContract.Groups}. Группа или группы, в которые входит необработанный контакт,
2314хранятся в таблице {@link android.provider.ContactsContract.Data} с использованием типа MIME
2315{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}.
2316</p>
2317<p>
2318    Если необходимо создать адаптер синхронизации, который будет добавлять данные необработанного контакта с сервера
2319в поставщик контактов, а вы не используете группы, то вам необходимо указать для поставщика,
2320чтобы он сделал ваши данные видимыми. В коде, который выполняется при добавлении пользователем
2321аккаунта на устройство, обновите строку {@link android.provider.ContactsContract.Settings},
2322которую поставщик контактов добавляет для этого аккаунта. В этой строке укажите в столбце
2323{@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE
2324Settings.UNGROUPED_VISIBLE} значение «1». После этого поставщик контактов всегда будет
2325делать ваши данные видимыми, даже если вы не используете группы.
2326</p>
2327<h3 id="Photos">Фотографии контактов</h3>
2328<p>
2329    В таблице {@link android.provider.ContactsContract.Data} хранятся фотографии в виде строк
2330{@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
2331Photo.CONTENT_ITEM_TYPE} типа MIME. Столбец
2332{@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} в строке связан со столбцом
2333{@code android.provider.BaseColumns#_ID} необработанного контакта, которому он принадлежит.
2334    Класс {@link android.provider.ContactsContract.Contacts.Photo} определяет вложенную таблицу
2335{@link android.provider.ContactsContract.Contacts}, в которой содержится информация об основной фотографии
2336контакта (которая является основной фотографией основного необработанного контакта этого контакта). Аналогичным образом класс
2337{@link android.provider.ContactsContract.RawContacts.DisplayPhoto} определяет вложенную таблицу
2338{@link android.provider.ContactsContract.RawContacts}, в которой содержится информация об основной фотографии
2339необработанного контакта.
2340</p>
2341<p>
2342    В справочной документации по {@link android.provider.ContactsContract.Contacts.Photo} и
2343{@link android.provider.ContactsContract.RawContacts.DisplayPhoto} содержатся примеры
2344получения информации о фотографии. К сожалению, отсутствует класс для удобного извлечения миниатюры
2345основной фотографии необработанного контакта, однако вы можете отправить запрос в таблицу
2346{@link android.provider.ContactsContract.Data}, выбрать
2347{@code android.provider.BaseColumns#_ID} необработанного контакта,
2348{@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
2349Photo.CONTENT_ITEM_TYPE} и столбец {@link android.provider.ContactsContract.Data#IS_PRIMARY},
2350чтобы найти строку основной фотографии необработанного контакта.
2351</p>
2352<p>
2353    Потоки данных из социальных сетей также могут включать фотографии. Они находятся в таблице
2354{@code android.provider.ContactsContract.StreamItemPhotos}, дополнительные сведения о которой представлены в разделе
2355<a href="#StreamPhotos">Фотографии из потока данных из социальных сетей</a>.
2356</p>
2357