• 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</a>
67
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 內容供應程式基本概念。如要更瞭解 Android 內容供應程式的詳細資訊,請閱讀<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">內容供應程式基本概念</a>指南。
114
115
116<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">範例同步配接器</a>範例應用程式是使用同步配接器在聯絡人供應程式和 Google 網路服務代管的範例應用程式之間傳輸資料的例子。
117
118
119
120</p>
121<h2 id="InformationTypes">聯絡人供應程式組織架構</h2>
122<p>
123    聯絡人供應程式是 Android 內容供應程式元件。負責維護三種與人有關的資料類型,每一種類型都會對應到供應程式所提供的表格,如圖 1 所示:
124
125
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    這三個表格通常會以其合約類別的名稱來稱呼。類別會定義內容 URI 的常數、欄名稱以及表格所使用的欄值:
133
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} 表格,而是儲存在 {@link android.provider.ContactsContract.Data} 表格中的一或多個列。
171每個資料列都有一欄
172{@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID},當中包含其上層資料列 {@link android.provider.ContactsContract.RawContacts} 的 {@code android.provider.BaseColumns#_ID RawContacts._ID} 值。
173
174
175</p>
176<h3 id="RawContactsColumns">重要的原始聯絡人欄</h3>
177<p>
178    {@link android.provider.ContactsContract.RawContacts} 表格中的重要欄列於表 1。
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 {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE}。
199
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            帳戶類型是此原始聯絡人的來源。例如,Google 帳戶的帳戶類型為 <code>com.google</code>。
212一定要將帳戶類型加上您所擁有或控制網域的網域識別碼。
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            原始聯絡人的「已刪除」旗標。
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} 的列,而是儲存在 {@link android.provider.ContactsContract.Data} 表格的
243 {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 列中。
244原始聯絡人在 {@link android.provider.ContactsContract.Data} 表格中只有一列這種類型。
245
246    </li>
247    <li>
248        <strong>注意:</strong>如要使用您在原始聯絡人列中自己的帳戶資料,必須先向 {@link android.accounts.AccountManager} 註冊。
249如要註冊,請提示使用者將帳戶類型及其帳戶名稱新增至帳戶清單。
250如果沒有這麼做,聯絡人供應程式將自動刪除您的原始聯絡人列。
251
252        <p>
253            例如,如果您希望應用程式維護網域為 {@code com.example.dataservice} 網頁式服務的聯絡人資料,此服務的使用者帳戶是 {@code becky.sharp@dataservice.example.com},這名使用者必須先新增帳戶「類型」({@code com.example.dataservice}) 和帳戶「名稱」
254({@code becky.smart@dataservice.example.com}),您的應用程式才能新增原始聯絡人列。
255
256
257
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>Twitter 帳戶「belle_of_amherst」</li>
272</ul>
273<p>
274    此使用者在「帳戶」<em></em>設定中為這三個帳戶啟用了「同步聯絡人」<em></em>。
275
276</p>
277<p>
278    假設 Emily Dickinson 開啟瀏覽器視窗,使用
279 <code>emily.dickinson@gmail.com</code>登入 Gmail,開啟[聯絡人] 並新增「Thomas Higginson」。
280接著,她使用
281 <code>emilyd@gmail.com</code>登入 Gmail,並寄送電子郵件給「Thomas Higginson」(系統已自動將他新增為聯絡人)。
282她也在 Twitter 上關注「colonel_tom」(Thomas Higginson 的 Twitter ID)。
283
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」相關聯。該使用者帳戶類型是 Twitter。
301
302    </li>
303</ol>
304<h2 id="DataBasics">資料</h2>
305<p>
306    如前所述,原始聯絡人的資料是儲存在
307 {@link android.provider.ContactsContract.Data} 列,而此列會連結到原始聯絡人的
308 <code>_ID</code> 值。這樣讓原始聯絡人的相同資料類型可以有多個執行個體,例如電子郵件地址或電話號碼。
309例如,如果{@code emilyd@gmail.com} 的 "Thomas Higginson" (Thomas Higginson 的原始聯絡人列,與 Google 帳戶 <code>emilyd@gmail.com</code> 關聯) 的住家電子郵件地址為
310 <code>thigg@gmail.com</code>,而工作電子郵件地址為
311 <code>thomas.higginson@gmail.com</code>,則聯絡人供應程式會儲存這兩個電子郵件地址列,並將兩者連結到原始聯絡人。
312
313
314
315</p>
316<p>
317    請注意,此單一表格中儲存了不同類型的資料。{@link android.provider.ContactsContract.Data} 表格中可以看到顯示名稱、電話號碼、電子郵件、郵寄地址、相片以及網站詳細資料等列。
318
319為了協助管理這些內容,
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 {@link android.provider.ContactsContract.CommonDataKinds} 子類別中定義的MIME 類型。
342這些 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例如,使用者長按聯絡人的電話號碼並選取 [設為預設值]<strong></strong>,則包含該號碼的 {@link android.provider.ContactsContract.Data} 列就會將它的 {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} 欄設為零以外的值。
352
353
354
355
356    </dd>
357</dl>
358<h3 id="GenericColumns">一般欄名稱</h3>
359<p>
360    一般欄有 15 個 (名稱為 <code>DATA1</code> 到
361 <code>DATA15</code>),系統通常會提供這些欄。另外有 4 個一般欄(<code>SYNC1</code> 到 <code>SYNC4</code>) 只能透過同步配接器使用。
362
363不管列中的資料類型為何,一定可以使用一般欄名稱常數。
364
365</p>
366<p>
367    <code>DATA1</code> 欄會建立索引。聯絡人供應程式一律會使用此欄的資料,而且供應程式預期此欄為最常查詢的目標。
368例如,在電子郵件列中,此欄內含實際的電子郵件地址。
369
370</p>
371<p>
372    一般來說,<code>DATA15</code> 欄會保留用於儲存「二進位大型物件」(BLOB) 資料,例如相片縮圖。
373
374</p>
375<h3 id="TypeSpecificNames">類型特定的欄名稱</h3>
376<p>
377    為了要協助欄處理具有特定類型的列,聯絡人供應程式也提供類型特定的欄名稱常數。這些常數會在
378 {@link android.provider.ContactsContract.CommonDataKinds}的子類別中定義。
379常數只是為相同欄名稱指定不同的常數名稱,以協助您存取列中特定類型的資料。
380
381
382</p>
383<p>
384    例如,{@link android.provider.ContactsContract.CommonDataKinds.Email} 類別定義了 {@link android.provider.ContactsContract.Data} 列的類型特定欄名稱常數。此列內含 MIME 類型 {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
385Email.CONTENT_ITEM_TYPE}。
386
387
388類別含有電子郵件地址欄的常數
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} 表格使用供應程式預先定義 MIME 類型的其中一種,請不要將您自訂的資料新增至此表格。
397假如將您自訂的資料新增至此表格,可能會遺失資料或讓供應程式發生故障。
398例如,您不應該將含有 MIME 類型 {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
399Email.CONTENT_ITEM_TYPE} (內含使用者名稱,而不是電子郵件地址) 的列新增至 <code>DATA1</code> 欄。
400
401如果您的列使用自訂 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        群組是帳戶類型和帳戶名稱的選用功能。如要進一步瞭解群組,請參閱<a href="#Groups">聯絡人群組</a>。
450
451    </td>
452  </tr>
453</table>
454<h3 id="ContactBasics">聯絡人</h3>
455<p>
456    聯絡人供應程式會合併所有帳戶類型和帳戶名稱的原始聯絡人,而成為「聯絡人」<strong></strong>。
457藉此協助使用者顯示及修改針對某個人所收集的所有資料。
458聯絡人供應程式負責建立新的聯絡人列,以及彙總原始聯絡人與現有的聯絡人列。
459應用程式或同步配接器都可以新增聯絡人,而聯絡人列中的某些欄屬於唯讀性質。
460
461</p>
462<p class="note">
463    <strong>注意:</strong>如果您嘗試使用
464 {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()} 將聯絡人新增至聯絡人供應程式,將會收到 {@link java.lang.UnsupportedOperationException} 例外狀況。
465如果您試著更新列為「唯讀」的欄,則會略過此更新作業。
466
467</p>
468<p>
469    如果新增的原始聯絡人與現有的聯絡人都不相符,聯絡人供應程式就會建立新的聯絡人。
470如果現有原始聯絡人的資料在變更後,不再與之前附加的聯絡人相符,則供應程式也會建立新的聯絡人。
471
472如果應用程式或同步配接器建立的新原始聯絡人「符合」<em></em>現有的聯絡人,則新的原始聯絡人會彙總為現有的聯絡人。
473
474
475</p>
476<p>
477    聯絡人供應程式使用 {@link android.provider.ContactsContract.Contacts Contacts} 表格中的聯絡人
478 <code>_ID</code> 欄,將聯絡人列連結到其原始聯絡人列。
479原始聯絡人表格
480 {@link android.provider.ContactsContract.RawContacts} 的 <code>CONTACT_ID</code> 欄,內含聯絡人列 (與每個原始聯絡人列相關聯) 的 <code>_ID</code> 值。
481
482</p>
483<p>
484    {@link android.provider.ContactsContract.Contacts} 表格也有
485{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} 欄,此為聯絡人列的「永久」連結。
486因為聯絡人供應程式會自動維護聯絡人,它會變更聯絡人列的 {@code android.provider.BaseColumns#_ID} 值,以回應彙總或同步操作。
487
488即使發生這種情況,與聯絡人的
489{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} 合併的內容 URI {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} 仍會指向聯絡人列,因此,您可以使用
490{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
491 來維護「常用聯絡人」等聯絡人的連結。
492
493此欄有自己的格式,與 {@code android.provider.BaseColumns#_ID} 欄的格式無關。
494
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    使用者將聯絡人資料直接輸入裝置,但資料也會過「同步配接器」從網路服務流入聯絡人供應程式<strong></strong> (同步配接器會自動將資料在裝置和服務之間傳輸)。
506
507同步配接器受到系統的控制、在背景執行,並且會呼叫 {@link android.content.ContentResolver} 方法來管理資料。
508
509
510</p>
511<p>
512    在 Android 中,與同步配接器搭配運作的網路服務,是透過帳戶類型加以識別。
513    每個同步配接器會與一種帳戶類型搭配,但可以支援該類型的多個帳戶名稱。
514帳戶類型和帳戶名稱在<a href="#RawContactsExample">原始聯絡人資料的來源</a>中會有更詳細的說明。
515 下列定義提供更詳細的資訊,說明帳戶類型和名稱與同步配接器和服務之間的關係。
516
517</p>
518<dl>
519    <dt>
520        帳戶類型
521    </dt>
522    <dd>
523        識別使用者儲存資料的服務。在大部分情況下,使用者必須經過服務的驗證。
524例如,Google 聯絡人是一種帳戶類型,由程式碼 <code>google.com</code> 加以識別。
525此值會對應到
526 {@link android.accounts.AccountManager} 所使用的帳戶類型。
527    </dd>
528    <dt>
529        帳戶名稱
530    </dt>
531    <dd>
532        識別特定帳戶或帳戶類型的登入。Google 聯絡人帳戶與 Google 帳戶相同,都是使用電子郵件地址做為帳戶名稱。
533
534        其他服務可能是以單一文字使用者名稱或數值 ID 做為帳戶名稱。
535    </dd>
536</dl>
537<p>
538    帳戶類型不必是唯一的。使用者可以設定多個 Google 聯絡人帳戶,並將其資料下載至聯絡人供應程式;如果使用者有一組個人帳戶名稱的個人聯絡人,還有另一組工作用的聯絡人,就可能發生此情形。
539
540帳戶名稱通常是唯一的。
541兩者加起來,就可以識別聯絡人供應程式和外部服務之間的特定資料流程。
542
543</p>
544<p>
545    如果您要將服務的資料傳輸到聯絡人供應程式,則需要編寫您自己的同步配接器。
546如要進一步瞭解同步配接器,請參閱<a href="#SyncAdapters">聯絡人供應程式同步配接器</a>。
547
548</p>
549<p>
550    圖 4 顯示聯絡人供應程式在人員相關的資料流程中所扮演的角色。
551在標記為「同步配接器」的方塊中,每個配接器都以其帳戶類型做為標籤。
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    這些權限不會延伸到使用者設定檔資料。如要瞭解使用者設定檔及其必要權限,請參閱<a href="#UserProfile">使用者設定檔</a>。
582
583
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    每個設定檔原始聯絡人列可以有多個資料列。{@link android.provider.ContactsContract.Profile} 類別中提供存取使用者設定檔的常數。
598
599</p>
600<p>
601    存取使用者設定檔需要特殊權限。除了
602{@link android.Manifest.permission#READ_CONTACTS} 和
603{@link android.Manifest.permission#WRITE_CONTACTS} 的讀取和寫入權限以外,存取使用者設定檔還分別需要 {@code android.Manifest.permission#READ_PROFILE} 讀取權限和
604{@code android.Manifest.permission#WRITE_PROFILE} 寫入權限。
605
606
607</p>
608<p>
609    請務必將使用者的設定檔視為敏感資訊。
610{@code android.Manifest.permission#READ_PROFILE}權限可以讓您存取裝置上使用者的身分識別資料。
611請務必在應用程式的簡介中告訴使用者,為何需要使用者設定檔存取權限。
612
613</p>
614<p>
615    如要擷取內含使用者的設定檔的聯絡人列,請呼叫 {@link android.content.ContentResolver#query(Uri,String[], String, String[], String)
616ContentResolver.query()}。
617將內容 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{@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} 欄。
644如果聯絡人為使用者設定檔,此欄會設為「1」。
645
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            標記裝置上經過變更,且必須同步回伺服器的原始聯絡人。
671Android 應用程式更新列時,聯絡人供應程式會自動設定此值。
672
673            <p>
674                修改原始聯絡人或資料表格的同步配接器一律會將字串{@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} 附加到其使用的內容 URI,
675
676藉此防止供應程式將列標記為已變更 (dirty)。
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            同步配接器建立新的原始聯絡人時,此欄應設為原始聯絡人的伺服器唯一 ID。
712Android 應用程式建立新的原始聯絡人時,應用程式應將此欄保留空白。
713這樣會提供訊號給同步配接器,要在伺服器上建立新的原始聯絡人,然後取得
714{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID} 值。
715
716            <p>
717                尤其是來源 ID 對於每個帳戶類型必須具備<strong>唯一性</strong>,在同步時應該很穩定:
718
719            </p>
720                <ul>
721                    <li>
722                        唯一:帳戶的每個原始聯絡人都必須有自己的來源 ID。如果沒有強制執行此條件,則聯絡人應用程式會發生問題。
723
724                        請注意,同一個帳戶「類型」<em></em>的兩個原始聯絡人可能會有相同的來源 ID。
725例如,{@code emily.dickinson@gmail.com} 帳戶的原始聯絡人「Thomas Higginson」與
726 {@code emilyd@gmail.com} 帳戶的原始聯絡人「Thomas Higginson」的來源 ID相同。
727
728
729                    </li>
730                    <li>
731                        穩定:來源 ID 是線上服務中原始聯絡人資料的永久部分。
732例如,如果使用者從應用程式設定中清除「聯絡人儲存空間」,然後重新同步,則還原的原始聯絡人的來源 ID 應該與先前相同。
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 應用程式 UI 中不應顯示此群組中的聯絡人。</td>
744        <td>
745            有些伺服器可以讓使用者隱藏某些群組中的聯絡人,此欄的設計提供了與這類伺服器的相容性。
746
747        </td>
748    </tr>
749    <tr>
750        <td>「1」:應用程式 UI 中會顯示此群組中的聯絡人。</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」:針對此帳戶和帳戶類型,Android 應用程式 UI 中不會顯示不屬於群組的聯絡人。
758
759        </td>
760        <td rowspan="2">
761            如果沒有任何原始聯絡人屬於某個群組,則聯絡人預設為不可見(原始聯絡人的群組成員資格是由{@link android.provider.ContactsContract.Data} 表格中的一或多個
762{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} 列所指出)。
763
764
765            在 {@link android.provider.ContactsContract.Settings} 表格列中為帳戶類型和帳戶設定此旗標,可以強制讓不屬於任何群組的聯絡人成為可見的。
766
767            此旗標的其中一個用途是,顯示伺服器中不屬於任何群組的聯絡人。
768        </td>
769    </tr>
770    <tr>
771        <td>
772            「1」:針對此帳戶和帳戶類型,應用程式 UI 中會顯示不屬於群組的聯絡人。
773
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    從同步配接器進行修改,在<a href="#SyncAdapters">聯絡人供應程式同步配接器</a>中也提供更詳細的資訊。
810
811</p>
812<h3 id="Entities">實體查詢</h3>
813<p>
814    因為聯絡人供應程式為階層式表格,擷取某一列及連結至此列的所有「子」列時非常實用。
815例如,如要顯示人員的所有資訊,您可能要擷取單一
816 {@link android.provider.ContactsContract.Contacts} 列的
817所有 {@link android.provider.ContactsContract.RawContacts} 列,或單一
818{@link android.provider.ContactsContract.RawContacts} 列的所有
819{@link android.provider.ContactsContract.CommonDataKinds.Email} 列。
820為了協助此操作,聯絡人供應程式提供<strong>實體</strong>建構,其運作方式就像是資料庫結合各個表格一樣。
821
822
823</p>
824<p>
825    實體就像是一份表格,由上層表格及其下層表格中的選取欄所組成。
826    查詢實體時,您會提供投影 (projection) 和搜尋條件根據該實體可用的欄。
827結果會是 {@link android.database.Cursor},擷取到的每個下層表格列在其中都會有一列。
828例如,如果您查詢
829{@link android.provider.ContactsContract.Contacts.Entity} 的聯絡人名稱,並且查詢所有 {@link android.provider.ContactsContract.CommonDataKinds.Email} 列中該名稱的所有原始聯絡人,則會取回 {@link android.database.Cursor},每個 {@link android.provider.ContactsContract.CommonDataKinds.Email} 列都會有一列。
830
831
832
833</p>
834<p>
835    實體簡化查詢。使用實體,您可以一次擷取聯絡人或原始聯絡人的所有聯絡人資料,而不用先查詢父項表格以取得 ID,再以此 ID 查詢子項表格。另外,聯絡人供應程式會在單一交易中處理針對實體的查詢,以確保所擷取的資料在內部的一致性。
836
837
838
839
840</p>
841<p class="note">
842    <strong>注意:</strong>實體通常不會包含上層表格和下層表格的所有欄。
843如果您嘗試使用的欄名稱未列在實體的欄名稱常數中,將會收到 {@link java.lang.Exception}。
844
845</p>
846<p>
847    以下程式碼片段展示如何擷取一位聯絡人的所有原始聯絡人列。此程式碼片段屬於大型應用程式的一部分,此應用程式有兩個 Activity:「主要」和「詳細」。
848主要 Activity 會顯示聯絡人列的清單,當使用者選取其中一項時,此 Activity 會將其 ID 傳送給詳細 Activity。
849
850詳細 Activity 會使用 {@link android.provider.ContactsContract.Contacts.Entity},針對所選取的聯絡人,顯示與其關聯的所有原始聯絡人的所有資料列。
851
852
853</p>
854<p>
855    此程式碼片段是取自「詳細」Activity:
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} 會呼叫 {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D)
925    onLoadFinished()} 的回呼。
926此方法的其中一個傳入引數是內含查詢結果的
927 {@link android.database.Cursor}。在您的應用程式中,您可以從這個 {@link android.database.Cursor} 取得資料,然後加以顯示或進一步處理。
928
929</p>
930<h3 id="Transactions">批次修改</h3>
931<p>
932    您應該儘可能透過建立
933 {@link android.content.ContentProviderOperation} 物件的{@link java.util.ArrayList},然後呼叫
934 {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()},以「批次模式」在聯絡人供應程式中進行資料的插入、更新以及刪除。
935因為聯絡人供應程式會在單一交易中執行
936{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} 的所有操作,所以您所做的修改不會讓聯絡人存放庫處於不一致的狀態。
937
938
939批次修改同時也有助於插入原始聯絡人及其詳細資料。
940
941</p>
942<p class="note">
943    <strong>注意:</strong>如要修改「單一」<em></em>原始聯絡人,請考慮將意圖傳送到裝置的聯絡人應用程式,而不要在您的應用程式中處理修改操作。這些動作在<a href="#Intents">使用意圖擷取和修改</a>中有更詳細的資料。
944
945
946
947</p>
948<h4>降伏點</h4>
949<p>
950    包含大量操作的批次修改可能會封鎖其他處理程序,導致整體的使用者體驗不良。
951如要將您想要執行的所有修改,儘可能安排在較少的清單中執行,同時要避免這些修改讓系統無法進行其他操作,則應該要為一或多個操作設定「降伏點」<strong></strong>。
952
953
954    降伏點是一個 {@link android.content.ContentProviderOperation} 物件,而且其
955{@link android.content.ContentProviderOperation#isYieldAllowed()} 值是設為
956<code>true</code>。當聯絡人供應程式遇到降伏點時,會暫停它的工作,以便讓其他處理程序執行,並關閉目前的交易。
957供應程式再次啟動時,會繼續 {@link java.util.ArrayList} 中的下一項操作,並啟動新的交易。
958
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 {@code android.provider.BaseColumns#_ID} 值做為
981{@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} 值,將資料列連結到原始聯絡人列。
982不過,此
983值在您為資料列建立 {@link android.content.ContentProviderOperation}
984時並不存在,這是因為您尚未替原始聯絡人列
985套用 {@link android.content.ContentProviderOperation}。為解決此狀況,{@link android.content.ContentProviderOperation.Builder} 類別提供了
986{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} 這個方法。
987
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
1008{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} 中的
1009{@link android.content.ContentProviderResult} 物件以 0 開始的陣列索引值。套用批次操作時,每次操作結果都會儲存在結果的中繼陣列。
1010
1011<code>previousResult</code> 值是這些結果的其中一個索引,這些結果是以 <code>key</code>值擷取並加以儲存。
1012
1013這樣可以讓您插入新的原始聯絡人記錄,並取得其
1014{@code android.provider.BaseColumns#_ID} 值,然後在您新增 {@link android.provider.ContactsContract.Data} 列時,做為此值的「反向參考」。
1015
1016            <p>
1017                您首次呼叫
1018 {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} 時會建立整個結果陣列,此陣列的大小等同於您所提供
1019 {@link android.content.ContentProviderOperation} 物件的{@link java.util.ArrayList} 大小。
1020不過,結果陣列中的所有元素會設為 <code>null</code>,如果您嘗試要針對尚未套用的操作結果製作反向參考,
1021{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}則會擲回 {@link java.lang.Exception}。
1022
1023
1024
1025
1026            </p>
1027        </dd>
1028    </dl>
1029<p>
1030    以下程式碼片段展示如何插入大量新的原始聯絡人和資料。其中包括建立降伏點和使用反向參考的程式碼。
1031此程式碼片段是 <code>createContacEntry()</code> 方法的擴充版本。而這個方法是
1032 <code><a href="{@docRoot}resources/samples/ContactManager/index.html">
1033    Contact Manager</a></code> 範例應用程式中
1034 <code>ContactAdder</code> 類別的一部分。
1035
1036</p>
1037<p>
1038    第一個程式碼片段會從 UI 擷取聯絡人資料。此時,使用者已經選好要加入的新原始聯絡人帳戶。
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{@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}。
1092參照會指向第一項操作中的 {@link android.content.ContentProviderResult} 物件 (第一項操作會新增原始聯絡人列,並傳回其新的 {@code android.provider.BaseColumns#_ID} 值)。
1093
1094
1095因此,每個資料列會透過其
1096{@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} 自動連結到它所屬的新 {@link android.provider.ContactsContract.RawContacts} 列。
1097
1098</p>
1099<p>
1100    新增電子郵件列的 {@link android.content.ContentProviderOperation.Builder} 物件會帶有 {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean)
1101    withYieldAllowed()} 旗標,而這會設定降伏點:
1102
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        使用
1230 {@link android.content.ContentProviderOperation#newAssertQuery(Uri)} 方法建立適合用於強制執行限制的{@link android.content.ContentProviderOperation.Builder} 物件。
1231如果是內容 URI,請使用 {@link android.provider.ContactsContract.RawContacts#CONTENT_URI
1232RawContacts.CONTENT_URI} 並附加原始聯絡人的 {@code android.provider.BaseColumns#_ID}。
1233
1234
1235    </li>
1236    <li>
1237        如果是 {@link android.content.ContentProviderOperation.Builder} 物件,請呼叫 {@link android.content.ContentProviderOperation.Builder#withValue(String, Object)
1238        withValue()},以比較 {@link android.provider.ContactsContract.SyncColumns#VERSION} 欄和您剛才擷取的版本號碼。
1239
1240
1241    </li>
1242    <li>
1243        如果是相同的 {@link android.content.ContentProviderOperation.Builder},請呼叫 {@link android.content.ContentProviderOperation.Builder#withExpectedCount(int)
1244withExpectedCount()} 以確保此判斷提示只測試一列。
1245
1246    </li>
1247    <li>
1248        呼叫 {@link android.content.ContentProviderOperation.Builder#build()} 以建立
1249{@link android.content.ContentProviderOperation} 物件,然後將此物件新增為您傳送到
1250 {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} 的第一個 {@link java.util.ArrayList} 物件。
1251
1252    </li>
1253    <li>
1254        套用批次交易。
1255    </li>
1256</ol>
1257<p>
1258    如果在您讀取原始聯絡人列和嘗試加以修改之間,有另一項操作要加以更新,則「判斷提示」{@link android.content.ContentProviderOperation} 將會失敗,而且整個批次的操作將會退出。
1259
1260您之後可以選擇重試此批次作業或採取其他動作。
1261
1262</p>
1263<p>
1264    以下程式碼片段展示如何在使用 {@link android.content.CursorLoader} 查詢單一原始聯絡人後,建立「判斷提示」
1265{@link android.content.ContentProviderOperation}:
1266
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意圖會啟動裝置的聯絡人應用程式 UI,使用者可以在此執行與聯絡人相關的工作。
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    當您透過裝置的聯絡人應用程式使用意圖來存取聯絡人供應程式時,不需要自已撰寫存取供應程式的 UI 或程式碼。
1329您也不需要要求供應程式的讀取或寫入權限。
1330裝置的聯絡人應用程式可以將某個聯絡人的讀取權限委派給您,而且因為是透過另一個應用程式對供應程式進行修改,所以不需要具備寫入權限。
1331
1332
1333</p>
1334<p>
1335    傳送意圖以存取供應程式的一般流程在<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">內容供應程式基本概念</a>指南的「透過意圖存取資料」中有詳細的說明。
1336
1337表 4 摘要說明您可以在工作中使用的動作、MIME 類型以及資料值,而您可以和
1338 {@link android.content.Intent#putExtra(String, String) putExtra()} 搭配使用的額外值則列於 {@link android.provider.ContactsContract.Intents.Insert} 的參考文件:
1339
1340
1341
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            顯示原始聯絡人清單或原始聯絡人的資料清單,視您提供的內容 URI 類型而定。
1384
1385            <p>
1386                呼叫
1387{@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()}可傳回所選取列的內容 URI。
1388URI 的格式是表格的內容 URI 附加列的 <code>LOOKUP_ID</code>。
1389
1390                裝置的聯絡人應用程式會在 Activity 的生命週期內,將讀取和寫入權限委派給此內容 URI。
1391詳情請參閱<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">內容供應程式基本概念</a>指南。
1392
1393
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()} 一起傳送,則新增的原始聯絡人內容 URI 會在 {@link android.content.Intent} 引數的 [資料] 欄位中傳回給 Activity 的
1409{@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}回呼方法。
1410
1411
1412如要取得此值,請呼叫 {@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編輯器 Activity 可讓使用者編輯與此聯絡人關聯的任何資料。
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> 來儲存編輯內容時,您的 Activity 會回到前景。
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()} 或 {@link android.content.ContentProviderOperation#newDelete(Uri)
1462ContentProviderOperation.newDelete()}。
1463
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.RawContacts} 列新增 {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 列。
1571
1572    </dt>
1573    <dd>
1574        {@link android.provider.ContactsContract.Data} 表格中不含
1575 {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 列的
1576{@link android.provider.ContactsContract.RawContacts} 列,在彙總時會造成問題。
1577
1578    </dd>
1579    <dt>
1580        務必將 {@link android.provider.ContactsContract.Data} 列連結到其上層的
1581{@link android.provider.ContactsContract.RawContacts} 列。
1582    </dt>
1583    <dd>
1584        裝置的聯絡人應用程式中將看不到未連結到
1585 {@link android.provider.ContactsContract.RawContacts} 的 {@link android.provider.ContactsContract.Data} 列,而且與同步配接器搭配使用時可能會造成問題。
1586
1587    </dd>
1588    <dt>
1589        只針對您擁有的原始聯絡人變更資料。
1590    </dt>
1591    <dd>
1592        請記住,聯絡人供應程式通常用來管理來自不同帳戶類型或線上服務的資料。
1593您必須確認應用程式只會修改或刪除屬於您的資料列,並且確認應用程式插入的資料只含有您可控制的帳戶類型和名稱。
1594
1595
1596    </dd>
1597    <dt>
1598        務必使用 {@link android.provider.ContactsContract} 及其子類別中定義的常數,做為授權、內容 URI、URI 路徑、欄名稱、MIME 類型以及
1599{@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE} 值。
1600
1601    </dt>
1602    <dd>
1603        使用這些常數可協助您避免發生錯誤。如果有任何常數已失效,則編譯器會發出通知。
1604
1605    </dd>
1606</dl>
1607<h3 id="CustomData">自訂資料列</h3>
1608<p>
1609    透過建立自訂的 MIME 類型,您可以插入、編輯、刪除以及擷取 {@link android.provider.ContactsContract.Data} 表格中您自己的資料列。
1610儘管您可以將自己的類型特定欄名稱對應到預設的欄名稱,您的列仍受限於使用
1611 {@link android.provider.ContactsContract.DataColumns} 中所定義的欄。
1612
1613在裝置的聯絡人應用程式中,可以顯示您的列中資料,但無法加以編輯或刪除,而且使用者無法新增其他資料。
1614
1615如要讓使用者修改您自訂的資料列,您必須在自己的應用程式中提供編輯器 Activity。
1616
1617</p>
1618<p>
1619    如要顯示自己的資料,請提供 <code>contacts.xml</code> 檔案,其中要包含
1620<code>&lt;ContactsAccountType&gt;</code> 元素以及一或多個其
1621<code>&lt;ContactsDataKind&gt;</code> 子元素。詳情請參閱 <a href="#SocialStreamDataKind"><code>&lt;ContactsDataKind&gt; element</code></a>一節。
1622
1623</p>
1624<p>
1625    如要更瞭解自訂 MIME 類型的詳細資訊,請閱讀<a href="{@docRoot}guide/topics/providers/content-provider-creating.html">建立內容供應程式</a>指南。
1626
1627
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    您將同步配接器實做為 {@link android.content.AbstractThreadedSyncAdapter} 的子類別,並以 Android 應用程式的一部分加以安裝。
1661
1662系統會從應用程式宣示說明中的元素,以及從宣示說明所指向的特殊 XML 檔案中瞭解同步配接器的相關資訊。
1663此 XML 檔案定義線上服務的帳戶類型,以及內容供應程式的授權,這兩者可用來唯一識別此配接器。
1664
1665同步配接器要在使用者新增同步配接器的帳戶類型,
1666並啟用要與同步配接器的內容供應程式同步後,
1667同步配接器才會變成使用中。此時,系統會開始管理配接器並視需要加以呼叫,以便在內容供應程式和伺服器之間進行同步。
1668
1669</p>
1670<p class="note">
1671    <strong>注意:</strong>使用帳戶類型做為同步配接器識別的一部分,可以讓系統在偵測後,將存取不同服務、但來自相同組織的同步配接器群組在一起。
1672
1673例如,Google 線上服務的同步配接器都有相同的帳戶類型 <code>com.google</code>。
1674使用者將 Google 帳戶新增至其裝置後,所有已安裝的 Google 服務同步配接器會列在一起,每個列出的同步配接器會與裝置上不同的內容供應程式進行同步。
1675
1676
1677</p>
1678<p>
1679    由於大多數服務都需要在存取資料之前先驗證其身分,因此 Android 系統提供類似的驗證架構,而且通常會與同步配接器架構一起搭配使用。
1680
1681驗證架構使用外掛程式驗證器,這是
1682 {@link android.accounts.AbstractAccountAuthenticator} 的子類別。
1683驗證器會以下列步驟驗證使用者的身分:
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} 可以存取驗證器支援且選擇顯示的任何 authtoken,例如 OAuth2 authtoken。
1701
1702</p>
1703<p>
1704    雖然驗證並非必要,大部分聯絡人服務仍會加以使用。
1705    不過,您不一定要使用 Android 驗證架構來進行驗證動作。
1706</p>
1707<h3 id="SyncAdapterImplementing">同步配接器實作</h3>
1708<p>
1709    如要實作聯絡人供應程式的同步配接器,要從建立內含以下各項的 Android 應用程式開始:
1710
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                在<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">範例同步配接器</a>範例應用程式中,此服務的名稱為
1724 <code>com.example.android.samplesync.syncadapter.SyncService</code>。
1725
1726            </p>
1727        </dd>
1728        <dt>
1729            實際的同步配接器是以
1730 {@link android.content.AbstractThreadedSyncAdapter} 的實體子類別加以實作。
1731        </dt>
1732        <dd>
1733            此類別會執行的工作包括:從伺服器下載資料、從裝置上傳資料以及解決衝突。
1734配接器的主要工作會使用 {@link android.content.AbstractThreadedSyncAdapter#onPerformSync(
1735Account, Bundle, String, ContentProviderClient, SyncResult)
1736onPerformSync()} 方法完成。
1737此類別必須以單一執行個體的方式加以具現化。
1738            <p>
1739                在<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">範例同步配接器</a>範例應用程式中,同步配接器定義在
1740<code>com.example.android.samplesync.syncadapter.SyncAdapter</code> 類別中。
1741
1742            </p>
1743        </dd>
1744        <dt>
1745            {@link android.app.Application} 的子類別。
1746        </dt>
1747        <dd>
1748            此類別就像是同步配接器單一執行個體的工廠。使用
1749{@link android.app.Application#onCreate()} 方法具現化同步配接器,並提供靜態的「getter」方法將單一執行個體傳回給同步配接器服務的
1750{@link android.app.Service#onBind(Intent) onBind()} 方法。
1751
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{@link android.app.Service#onBind(Intent) onBind()} 方法以取得驗證器的
1763 {@link android.os.IBinder}。
1764這樣可以讓系統以跨處理程序的方式呼叫驗證器的方法。
1765
1766            <p>
1767                在<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">範例同步配接器</a>範例應用程式中,此服務的類別名稱為
1768<code>com.example.android.samplesync.authenticator.AuthenticationService</code>。
1769
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                在<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">範例同步配接器</a>範例應用程式中,驗證器是在
1784<code>com.example.android.samplesync.authenticator.Authenticator</code> 類別中完成定義。
1785
1786            </p>
1787        </dd>
1788        <dt>
1789            定義系統同步配接器和驗證器的 XML 檔案。
1790        </dt>
1791        <dd>
1792            應用程式宣示說明中的
1793 <code>&lt;<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>&gt;</code> 元素會定義之前說明的同步配接器和驗證器服務元件。
1794
1795這些元素包含的
1796<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code> 子元素可提供系統的特定資料:
1797
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> 元素,此元素會指向 XML 檔案 <code>res/xml/syncadapter.xml</code>。
1804
1805此檔案會按順序指出
1806將與聯絡人供應程式同步的網路服務 URI,
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> 元素,此元素會指向 XML 檔案
1812<code>res/xml/authenticator.xml</code>。
1813此檔案會按順序指出此驗證器支援的帳戶類型,以及驗證程序中會出現的 UI 資源。
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{@code android.provider.ContactsContract.StreamItemPhotos} 表格負責管理社交網路的傳入資料。
1826您可以編寫一個同步配接器,將來自您自己網路的串流資料
1827新增至這些表格,或是可以從這些表格讀取串流資料,然後
1828顯示於您自己的應用程式中,或同時具備這兩種功能。有了這些功能,您的社交網路服務和應用程式就可以整合到 Android 的社交網路體驗。
1829
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{@link android.text.Html#fromHtml(String) fromHtml()} 能夠轉譯的任何格式內嵌資源影像。
1893供應程式會截斷較長的內容,但會試著避免破壞標籤。
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} 到
1916{@code android.provider.ContactsContract.StreamItemsColumns#SYNC4} 欄,專門供同步配接器使用。
1917
1918</p>
1919<h3 id="StreamPhotos">社交串流相片</h3>
1920<p>
1921   {@code android.provider.ContactsContract.StreamItemPhotos} 表格會儲存與串流項目相關聯的相片。
1922表格的
1923{@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID} 欄會連結到
1924 {@code android.provider.ContactsContract.StreamItems} 表格中 {@code android.provider.BaseColumns#_ID} 欄的值。
1925相片參照會儲存在表格中的以下各欄:
1926
1927</p>
1928<dl>
1929    <dt>
1930        {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} 欄 (BLOB)。
1931    </dt>
1932    <dd>
1933        相片的二進位檔,由供應程式調整大小以進行儲存和顯示。
1934        此欄是要提供與使用舊版聯絡人供應程式儲存相片的向下相容性。
1935不過,在目前版本中,您不應使用此欄來儲存相片。
1936請改用 {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} 或
1937{@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} (下文提供這兩者的相關說明) 在檔案中儲存相片。
1938
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} 可取得指向單一相片檔案的內容 URI,然後呼叫 {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
1948openAssetFileDescriptor()} 可取得此相片檔案的控制代碼。
1949
1950
1951    </dd>
1952    <dt>
1953        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI}
1954    </dt>
1955    <dd>
1956        直接指向此列所呈現相片的相片檔案內容 URI。
1957        使用此 URI 呼叫 {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
1958openAssetFileDescriptor()} 可取得相片檔案的控制代碼。
1959    </dd>
1960</dl>
1961<h3 id="SocialStreamTables">使用社交串流表格</h3>
1962<p>
1963    這些表格的運作方式與聯絡人供應程式中的其他主要表格大致相同,以下各項除外:
1964</p>
1965    <ul>
1966        <li>
1967            這些表格需要額外的存取權限。如要從中讀取,您的應用程式必須具備 {@code android.Manifest.permission#READ_SOCIAL_STREAM} 權限。
1968如要加以修改,您的應用程式必須具備
1969{@code android.Manifest.permission#WRITE_SOCIAL_STREAM} 權限。
1970
1971        </li>
1972        <li>
1973            針對 {@code android.provider.ContactsContract.StreamItems} 表格,每個原始聯絡人的儲存列數是有限制的。
1974達到此限制後,聯絡人供應程式會自動刪除
1975{@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} 最舊的列,為新的串流項目列騰出空間。
1976
1977如要取得此限制,請發出查詢給內容 URI
1978{@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI}。
1979您只要將內容 URI 設為 <code>null</code> 即可,其餘引數不需要處理。
1980此查詢會傳回內含單一列的 Cursor 與單一欄
1981{@code android.provider.ContactsContract.StreamItems#MAX_ITEMS}。
1982
1983        </li>
1984    </ul>
1985
1986<p>
1987    類別 {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} 定義了單一串流項目,且內含相片列的 {@code android.provider.ContactsContract.StreamItemPhotos} 子表格。
1988
1989
1990</p>
1991<h3 id="SocialStreamInteraction">社交串流互動</h3>
1992<p>
1993    社交串流資料受到聯絡人供應程式與裝置聯絡人應用程式的管理,提供強大的方式將您的社交網路系統與現有聯絡人連接起來。
1994
1995提供下列功能:
1996</p>
1997    <ul>
1998        <li>
1999            使用同步配接器將您的社交網路服務同步到聯絡人供應程式後,您可以擷取某位使用者的聯絡人最近 Activity,並將它儲存在 {@code android.provider.ContactsContract.StreamItems} 和
2000{@code android.provider.ContactsContract.StreamItemPhotos} 表格中,供後續使用。
2001
2002
2003        </li>
2004        <li>
2005            除了一般同步之外,您可以在使用者選取要檢視的聯絡人時,觸發您的同步配接器,以擷取其他資料。
2006此舉可讓您的同步配接器擷取聯絡人高解析度的相片,以及聯絡人最近的串流項目。
2007
2008        </li>
2009        <li>
2010            藉由向裝置的聯絡人應用程式和聯絡人供應程式註冊通知,您可以在檢視聯絡人時「收到」<em></em>意圖,並於此時更新您服務中的聯絡人狀態。
2011
2012相較於與同步配接器執行完整同步,
2013此方式較快速且使用的頻寬較少。
2014        </li>
2015        <li>
2016            使用者在裝置的聯絡人應用程式查看聯絡人時,可以將聯絡人新增至您的社交網路服務。
2017您可以透過「邀請聯絡人」啟用上述功能。「邀請聯絡人」會啟用一連串的 Activity,將現有聯絡人新增至您的網路和 XML 檔案。此檔案會將您應用程式的詳細資訊提供給裝置的聯絡人應用程式和聯絡人供應程式。
2018
2019
2020
2021        </li>
2022    </ul>
2023<p>
2024    串流項目與聯絡人供應程式的一般同步與其他同步相同。
2025如要進一步瞭解同步,請參閱<a href="#SyncAdapters">聯絡人供應程式同步配接器</a>。
2026以下兩節說明如何註冊通知和邀請聯絡人。
2027
2028</p>
2029<h4>註冊以處理社交網路檢視</h4>
2030<p>
2031    註冊您的同步配接器,使其在使用者查看由您的同步配接器所管理的聯絡人時收到通知:
2032
2033</p>
2034<ol>
2035    <li>
2036        在專案的 <code>res/xml/</code> 目錄中建立名稱為 <code>contacts.xml</code>的檔案。
2037如果已經有這個檔案,可略過此步驟。
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 <code>viewContactNotifyService="<em>serviceclass</em>"</code> 屬性新增至此元素,其中
2047 <code><em>serviceclass</em></code> 是該服務的完整類別名稱,而此服務會收到來自裝置聯絡人應用程式的意圖。
2048
2049對於通知器服務而言,使用擴充 {@link android.app.IntentService} 的類別可以讓此服務接收意圖。
2050
2051傳入意圖的資料中含有使用者所點擊該名原始聯絡人的內容 URI。
2052您可以從通知器服務繫結,然後呼叫您的同步配接器,以更新原始聯絡人的資料。
2053
2054    </li>
2055</ol>
2056<p>
2057    如何註冊使用者點擊串流項目或相片 (或兩者) 時所呼叫的 Activity:
2058</p>
2059<ol>
2060    <li>
2061        在專案的 <code>res/xml/</code> 目錄中建立名稱為 <code>contacts.xml</code>的檔案。
2062如果已經有這個檔案,可略過此步驟。
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        為了註冊其中一個 Activity,讓它處理使用者在裝置的聯絡人應用程式中點擊串流項目的 Activity,請將
2071 <code>viewStreamItemActivity="<em>activityclass</em>"</code> 屬性新增至此元素,其中
2072 <code><em>activityclass</em></code> 是該 Activity 的完整類別名稱,而此 Activity 會收到來自裝置聯絡人應用程式的意圖。
2073
2074
2075    </li>
2076    <li>
2077        為了註冊其中一個 Activity,讓它處理使用者在裝置的聯絡人應用程式中點擊串流相片的活動,請將
2078 <code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> 屬性新增至此元素,其中
2079 <code><em>activityclass</em></code> 是該 Activity 的完整類別名稱,而此 Activity 會收到來自裝置聯絡人應用程式的意圖。
2080
2081
2082    </li>
2083</ol>
2084<p>
2085    如要進一步瞭解 <code>&lt;ContactsAccountType&gt;</code> 元素,請參閱 <a href="#SocialStreamAcctType">&lt;ContactsAccountType&gt; 元素</a>。
2086
2087</p>
2088<p>
2089    傳入意圖的資料中含有使用者所按下項目或相片的內容 URI。
2090    如要針對文字項目和相片採取不同的 Activity,請在相同的檔案中同時使用兩個屬性。
2091</p>
2092<h4>與社交網路服務互動</h4>
2093<p>
2094    使用者不需要離開裝置的聯絡人應用程式,就可以邀請聯絡人到您的社交網路網站。
2095您可以改為讓裝置的聯絡人應用程式傳送意圖,以邀請聯絡人前往您的 Activity。
2096如要進行此設定:
2097</p>
2098<ol>
2099    <li>
2100        在專案的 <code>res/xml/</code> 目錄中建立名稱為 <code>contacts.xml</code>的檔案。
2101如果已經有這個檔案,可略過此步驟。
2102    </li>
2103    <li>
2104        在此檔案中,新增 <code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code> 元素。
2105
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> 值是 Activity 的完整類別名稱,以此 Activity 接收意圖。
2117<code><em>invite_action_label</em></code> 值是顯示在裝置聯絡人應用程式內 [新增連線]<strong></strong> 選單中的文字字串。
2118
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    宣告 Android 元件和 UI 標籤,讓使用者可以邀請聯絡人加入社交網路、使用者的社交網路串流更新內容時通知使用者等等。
2165
2166
2167</p>
2168<p>
2169    請注意,<code>&lt;ContactsAccountType&gt;</code> 的屬性不需要使用屬性前置詞 <code>android:</code>。
2170
2171</p>
2172<p>
2173    <strong>屬性:</strong>
2174</p>
2175<dl>
2176    <dt>{@code inviteContactActivity}</dt>
2177    <dd>
2178        使用者從裝置的聯絡人應用程式選取[新增連線]<strong></strong>時,您希望在應用程式中啟動的 Activity 完整類別名稱。
2179
2180
2181    </dd>
2182    <dt>{@code inviteContactActionLabel}</dt>
2183    <dd>
2184        在 [新增連線]<strong></strong> 選單的
2185 {@code inviteContactActivity} 中所指定 Activity 的顯示文字字串。
2186        例如,您可以使用「關注我的網路活動」字串。此標籤可以使用字串資源識別碼。
2187
2188    </dd>
2189    <dt>{@code viewContactNotifyService}</dt>
2190    <dd>
2191        使用者檢視聯絡人時,要接收通知的應用程式中的服務完整類別名稱。
2192此通知是由裝置的聯絡人應用程式所傳送,這樣可以讓您的應用程式延後要處理大量資料的操作,需要時再加以處理。
2193
2194例如,您的應用程式可以藉由讀取並顯示聯絡人的高解析度相片,以及最近的社交串流項目,以回應此通知。
2195
2196如要進一步瞭解此功能,請參閱<a href="#SocialStreamInteraction">社交串流互動</a>。
2197您可以在
2198 <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a> 範例應用程式的 <code>NotifierService.java</code>中查看通知服務的範例。
2199
2200
2201    </dd>
2202    <dt>{@code viewGroupActivity}</dt>
2203    <dd>
2204        應用程式中可以顯示群組資訊的 Activity 完整類別名稱。
2205使用者在裝置的聯絡人應用程式中按一下群組標籤時,會顯示此 Activity 的 UI。
2206
2207    </dd>
2208    <dt>{@code viewGroupActionLabel}</dt>
2209    <dd>
2210        聯絡人應用程式顯示 UI 控制項的標籤,可以讓使用者在您的應用程式中查看群組。
2211
2212        <p>
2213            例如,如果您在裝置上安裝 Google+ 應用程式,而您將Google+ 與聯絡人應用程式進行同步,您會看到 Google+ 社交圈已列為聯絡人應用程式 [群組]<strong></strong> 標籤中的群組。
2214
2215如果按一下 Google+ 社交圈,您會看到該社交圈中的人員已列為「群組」。
2216系統會在畫面頂端顯示 Google+ 圖示,如果您按一下此圖示,則控制權會切換到 Google+ 應用程式。聯絡人應用程式使用
2217{@code viewGroupActivity} 執行此動作,並使用 Google+ 圖示做為
2218{@code viewGroupActionLabel} 的值。
2219
2220
2221        </p>
2222        <p>
2223            此屬性可以使用字串資源識別碼。
2224        </p>
2225    </dd>
2226    <dt>{@code viewStreamItemActivity}</dt>
2227    <dd>
2228        使用者按一下原始聯絡人的串流項目時,裝置的聯絡人應用程式所啟動應用程式中的 Activity 完整類別名稱。
2229
2230    </dd>
2231    <dt>{@code viewStreamItemPhotoActivity}</dt>
2232    <dd>
2233        使用者按一下原始聯絡人串流項目中的相片時,裝置的聯絡人應用程式所啟動應用程式中的 Activity 完整類別名稱。
2234
2235
2236    </dd>
2237</dl>
2238<h4 id="SocialStreamDataKind">&lt;ContactsDataKind&gt; 元素</h4>
2239<p>
2240    <code>&lt;ContactsDataKind&gt;</code> 元素控制聯絡人應用程式的 UI 中,您的應用程式自訂資料列所顯示的控制項。此元素的語法如下:
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;ContactsAccountType&gt;</code> 的每個 <code>&lt;ContactsDataKind&gt;</code> 子元素都代表同步配接器新增至 {@link android.provider.ContactsContract.Data} 表格的自訂資料列類型。
2260
2261針對您使用的每個自訂 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        您在
2272 {@link android.provider.ContactsContract.Data} 表格中已經為自訂資料列類型所定義的自訂 MIME 類型。例如,
2273<code>vnd.android.cursor.item/vnd.example.locationstatus</code> 值可能是
2274記錄聯絡人最後已知位置資料列的自訂 MIME 類型。
2275    </dd>
2276    <dt>{@code android:icon}</dt>
2277    <dd>
2278        聯絡人應用程式顯示在資料旁邊的 Android
2279<a href="{@docRoot}guide/topics/resources/drawable-resource.html">可繪資源</a>。
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    聯絡人供應程式可以選擇為群組<strong></strong>資料相關的聯絡人集合貼上標籤。
2309如果與使用者帳戶關聯的伺服器要維護群組,該帳戶的帳戶類型所屬的同步配接器,應該要在聯絡人供應程式和伺服器之間傳輸群組資料。
2310
2311使用者將新的聯絡人新增至伺服器,然後將此聯絡人放置於新群組時,同步配接器必須將新群組新增至 {@link android.provider.ContactsContract.Groups} 表格。
2312
2313原始聯絡人所屬的一或多個群組會使用 {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} MIME 類型儲存在 {@link android.provider.ContactsContract.Data} 表格。
2314
2315
2316</p>
2317<p>
2318    如果您設計的同步配接器,會將原始聯絡人資料從伺服器新增至聯絡人供應程式,表示您並未使用群組,那麼您需要告訴供應程式讓您的資料變成可見的。
2319
2320在使用者將帳戶新增至裝置時,要執行的程式碼中,更新聯絡人供應程式為帳戶新增的 {@link android.provider.ContactsContract.Settings} 列。
2321
2322在此列中,將 {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE
2323Settings.UNGROUPED_VISIBLE} 欄的值設為 1。
2324這麼做之後,即使您沒有使用群組,聯絡人供應程式
2325一律會讓您的聯絡人資料成為可見的。
2326</p>
2327<h3 id="Photos">聯絡人相片</h3>
2328<p>
2329    {@link android.provider.ContactsContract.Data} 表格會使用 MIME 類型 {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
2330Photo.CONTENT_ITEM_TYPE} 在列中儲存相片。
2331列的
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} 定義了 {@link android.provider.ContactsContract.RawContacts} 的子表格,其中包含原始聯絡人之主要相片的相片資訊。
2338
2339
2340</p>
2341<p>
2342    {@link android.provider.ContactsContract.Contacts.Photo} 和
2343{@link android.provider.ContactsContract.RawContacts.DisplayPhoto} 的參考文件含有擷取相片資訊的範例。
2344擷取原始聯絡人的主要縮圖沒有方便使用的類別,不過您可以傳送查詢到
2345{@link android.provider.ContactsContract.Data} 表格,然後選取原始聯絡人的
2346{@code android.provider.BaseColumns#_ID}、{@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
2347Photo.CONTENT_ITEM_TYPE} 以及 {@link android.provider.ContactsContract.Data#IS_PRIMARY} 欄,以尋找原始聯絡人的主要相片列。
2348
2349
2350
2351</p>
2352<p>
2353    人員的社交串流資料可能也包括相片。這些資訊都儲存在
2354{@code android.provider.ContactsContract.StreamItemPhotos} 表格。<a href="#StreamPhotos">社交串流相片</a>中針對此表格會有更詳細的說明。
2355
2356</p>
2357