• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Nội dung Cơ bản về Trình cung cấp Nội dung
2@jd:body
3<div id="qv-wrapper">
4<div id="qv">
5<!-- In this document -->
6<h2>Trong tài liệu này</h2>
7<ol>
8    <li>
9        <a href="#Basics">Tổng quan</a>
10        <ol>
11            <li>
12                <a href="#ClientProvider">Truy cập một trình cung cấp</a>
13            </li>
14            <li>
15                <a href="#ContentURIs">URI Nội dung</a>
16            </li>
17        </ol>
18    </li>
19    <li>
20        <a href="#SimpleQuery">Truy xuất Dữ liệu từ Trình cung cấp</a>
21        <ol>
22            <li>
23                <a href="#RequestPermissions">Yêu cầu quyền truy cập đọc</a>
24            </li>
25            <li>
26                <a href="#Query">Xây dựng truy vấn</a>
27            </li>
28            <li>
29                <a href="#DisplayResults">Hiển thị các kết quả truy vấn</a>
30            </li>
31            <li>
32                <a href="#GettingResults">Lấy dữ liệu từ các kết quả truy vấn</a>
33            </li>
34        </ol>
35    </li>
36    <li>
37        <a href="#Permissions">Quyền của Trình cung cấp Nội dung</a>
38    </li>
39    <li>
40        <a href="#Modifications">Chèn, Cập nhật, và Xóa Dữ liệu</a>
41        <ol>
42            <li>
43                <a href="#Inserting">Chèn dữ liệu</a>
44            </li>
45            <li>
46                <a href="#Updating">Cập nhật dữ liệu</a>
47            </li>
48            <li>
49                <a href="#Deleting">Xóa dữ liệu</a>
50            </li>
51        </ol>
52    </li>
53    <li>
54        <a href="#DataTypes">Các Kiểu Dữ liệu của Trình cung cấp</a>
55    </li>
56    <li>
57        <a href="#AltForms">Các Hình thức Truy cập Trình cung cấp Thay thế</a>
58        <ol>
59            <li>
60                <a href="#Batch">Truy cập hàng loạt</a>
61            </li>
62            <li>
63                <a href="#Intents">Truy cập dữ liệu thông qua ý định</a>
64            </li>
65        </ol>
66    </li>
67    <li>
68        <a href="#ContractClasses">Các Lớp Hợp đồng</a>
69    </li>
70    <li>
71        <a href="#MIMETypeReference">Tham khảo Kiểu MIME</a>
72    </li>
73</ol>
74
75    <!-- Key Classes -->
76<h2>Lớp khóa</h2>
77    <ol>
78        <li>
79            {@link android.content.ContentProvider}
80        </li>
81        <li>
82            {@link android.content.ContentResolver}
83        </li>
84        <li>
85            {@link android.database.Cursor}
86        </li>
87        <li>
88            {@link android.net.Uri}
89        </li>
90    </ol>
91
92    <!-- Related Samples -->
93<h2>Các Mẫu Liên quan</h2>
94    <ol>
95        <li>
96        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
97        Con chạy (Danh bạ)</a>
98        </li>
99        <li>
100        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
101        Con chạy (Điện thoại)</a>
102        </li>
103    </ol>
104
105    <!-- See also -->
106<h2>Xem thêm</h2>
107    <ol>
108        <li>
109            <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
110            Tạo một Trình cung cấp Nội dung</a>
111        </li>
112        <li>
113            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
114            Trình cung cấp Lịch</a>
115        </li>
116    </ol>
117</div>
118</div>
119
120    <!-- Intro paragraphs -->
121<p>
122    Trình cung cấp nội dung quản lý truy cập vào một kho dữ liệu tập trung. Trình cung cấp
123    là bộ phận của một ứng dụng Android, nó thường cung cấp UI của chính mình để làm việc cùng
124    dữ liệu. Tuy nhiên, trình cung cấp nội dung được thiết kế chủ yếu cho các ứng dụng khác
125    sử dụng, giúp truy cập trình cung cấp bằng cách sử dụng một đối tượng máy khách cung cấp. Cùng nhau, trình cung cấp
126    và máy khách cung cấp sẽ mang đến một giao diện nhất quán, tiêu chuẩn cho dữ liệu, giao diện này
127    cũng đồng thời xử lý truyền thông liên tiến trình và bảo mật truy cập dữ liệu.
128</p>
129<p>
130    Chủ đề này đề cập đến những nội dung cơ bản sau đây:
131</p>
132    <ul>
133        <li>Cách trình cung cấp nội dung hoạt động.</li>
134        <li>API bạn sử dụng để truy xuất dữ liệu từ một trình cung cấp nội dung.</li>
135        <li>API bạn sử dụng để chèn, cập nhật, hoặc xóa dữ liệu trong một trình cung cấp nội dung.</li>
136        <li>Các tính năng API khác tạo điều kiện làm việc cùng các trình cung cấp.</li>
137    </ul>
138
139    <!-- Basics -->
140<h2 id="Basics">Tổng quan</h2>
141<p>
142    Trình cung cấp nội dung trình bày dữ liệu cho các ứng dụng bên ngoài dưới dạng một hoặc nhiều bảng tương tự
143    như các bảng được tìm thấy trong một cơ sở dữ liệu quan hệ. Mỗi hàng thể hiện một thực thể của một số kiểu dữ liệu
144    mà trình cung cấp thu thập, và mỗi cột trong hàng thể hiện một phần riêng biệt của dữ liệu được thu thập
145    đối với một thực thể.
146</p>
147<p>
148    Ví dụ, một trong các trình cung cấp tích hợp trong nền tảng Android đó là từ điển người dùng, nó
149    lưu giữ chính tả của những từ phi tiêu chuẩn mà người dùng muốn giữ lại. Bảng 1 minh họa
150    cách mà dữ liệu có thể được trình bày trong bảng của trình cung cấp này:
151</p>
152<p class="table-caption">
153    <strong>Bảng 1:</strong> Bảng từ điển người dùng mẫu.
154</p>
155<table id="table1" style="width: 50%;">
156    <tr>
157        <th style="width:20%" align="center" scope="col">từ</th>
158        <th style="width:20%" align="center" scope="col">id ứng dụng</th>
159        <th style="width:20%" align="center" scope="col">tần suất</th>
160        <th style="width:20%" align="center" scope="col">bản địa</th>
161        <th style="width:20%" align="center" scope="col">_ID</th>
162    </tr>
163    <tr>
164        <td align="center" scope="row">mapreduce</td>
165        <td align="center">user1</td>
166        <td align="center">100</td>
167        <td align="center">en_US</td>
168        <td align="center">1</td>
169    </tr>
170    <tr>
171        <td align="center" scope="row">precompiler</td>
172        <td align="center">user14</td>
173        <td align="center">200</td>
174        <td align="center">fr_FR</td>
175        <td align="center">2</td>
176    </tr>
177    <tr>
178        <td align="center" scope="row">applet</td>
179        <td align="center">user2</td>
180        <td align="center">225</td>
181        <td align="center">fr_CA</td>
182        <td align="center">3</td>
183    </tr>
184    <tr>
185        <td align="center" scope="row">const</td>
186        <td align="center">user1</td>
187        <td align="center">255</td>
188        <td align="center">pt_BR</td>
189        <td align="center">4</td>
190    </tr>
191    <tr>
192        <td align="center" scope="row">int</td>
193        <td align="center">user5</td>
194        <td align="center">100</td>
195        <td align="center">en_UK</td>
196        <td align="center">5</td>
197    </tr>
198</table>
199<p>
200    Trong bảng 1, mỗi hàng thể hiện một thực thể của một từ mà có thể không thấy có
201    trong từ điển chuẩn. Mỗi cột thể hiện một số dữ liệu cho từ đó, chẳng hạn như
202    từ bản địa được dùng lần đầu cho từ đó. Tiêu đề cột là các tên cột được lưu giữ trong
203    trình cung cấp. Để tham khảo tới bản địa của một hàng, bạn tham khảo tới cột <code>locale</code> của hàng đó. Đối với
204    trình cung cấp này, cột <code>_ID</code> đóng vai trò là cột "khóa chính" mà
205    trình cung cấp tự động duy trì.
206</p>
207<p class="note">
208    <strong>Lưu ý:</strong> Trình cung cấp không bắt buộc phải có một khóa chính, và không bắt buộc phải
209    sử dụng <code>_ID</code> làm tên cột của một khóa chính nếu có khóa. Tuy nhiên,
210    nếu bạn muốn gắn kết dữ liệu từ một trình cung cấp với một {@link android.widget.ListView}, một trong các
211    tên cột sẽ phải là <code>_ID</code>. Yêu cầu này được giải thích chi tiết hơn trong
212    phần <a href="#DisplayResults">Hiển thị các kết quả truy vấn</a>.
213</p>
214<h3 id="ClientProvider">Truy cập một trình cung cấp</h3>
215<p>
216    Một ứng dụng truy cập dữ liệu từ một trình cung cấp nội dung bằng
217    một đối tượng máy khách {@link android.content.ContentResolver}. Đối tượng này có các phương pháp để gọi
218    những phương pháp có tên giống nhau trong đối tượng trình cung cấp, một thực thể của một trong những lớp con
219    cụ thể của {@link android.content.ContentProvider}. Các phương pháp
220    {@link android.content.ContentResolver} cung cấp các chức năng
221    "CRUD" (tạo, truy xuất, cập nhật, và xóa) cơ bản của thiết bị lưu trữ liên tục.
222</p>
223<p>
224    Đối tượng {@link android.content.ContentResolver} trong tiến trình
225    của ứng dụng máy khách và đối tượng {@link android.content.ContentProvider} trong ứng dụng mà sở hữu
226    trình cung cấp sẽ tự động xử lý truyền thông liên tiến trình.
227    {@link android.content.ContentProvider} cũng đóng vai trò như một lớp rút gọn giữa kho dữ liệu
228    của nó và biểu diễn bên ngoài của dữ liệu dưới dạng bảng.
229</p>
230<p class="note">
231    <strong>Lưu ý:</strong> Để truy cập một trình cung cấp, ứng dụng của bạn thường phải yêu cầu các quyền
232    cụ thể trong tệp bản kê khai của mình. Điều này được mô tả chi tiết hơn trong phần
233    <a href="#Permissions">Quyền của Trình cung cấp Nội dung</a>
234</p>
235<p>
236    Ví dụ, để có một danh sách các từ và nội dung bản địa của chúng từ Trình cung cấp Từ điển Người dùng,
237    bạn hãy gọi {@link android.content.ContentResolver#query ContentResolver.query()}.
238    Phương pháp {@link android.content.ContentResolver#query query()} sẽ gọi phương pháp
239    {@link android.content.ContentProvider#query ContentProvider.query()} được định nghĩa bởi
240    Trình cung cấp Từ điển Người dùng. Các dòng mã sau thể hiện một lệnh gọi
241    {@link android.content.ContentResolver#query ContentResolver.query()}:
242<p>
243<pre>
244// Queries the user dictionary and returns results
245mCursor = getContentResolver().query(
246    UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
247    mProjection,                        // The columns to return for each row
248    mSelectionClause                    // Selection criteria
249    mSelectionArgs,                     // Selection criteria
250    mSortOrder);                        // The sort order for the returned rows
251</pre>
252<p>
253    Bảng 2 cho biết các tham đối tới
254    {@link android.content.ContentResolver#query
255    query(Uri,projection,selection,selectionArgs,sortOrder)} khớp với một câu lệnh SQL SELECT như thế nào:
256</p>
257<p class="table-caption">
258    <strong>Bảng 2:</strong> Query() so với truy vấn SQL.
259</p>
260<table id="table2" style="width: 75%;">
261    <tr>
262        <th style="width:25%" align="center" scope="col">tham đối query()</th>
263        <th style="width:25%" align="center" scope="col">Từ khóa/tham số SELECT</th>
264        <th style="width:50%" align="center" scope="col">Lưu ý</th>
265    </tr>
266    <tr>
267        <td align="center"><code>Uri</code></td>
268        <td align="center"><code>FROM <em>table_name</em></code></td>
269        <td><code>Uri</code> ánh xạ tới bảng trong trình cung cấp có tên <em>table_name</em>.</td>
270    </tr>
271    <tr>
272        <td align="center"><code>projection</code></td>
273        <td align="center"><code><em>col,col,col,...</em></code></td>
274        <td>
275            <code>projection</code> là một mảng gồm các cột nên được đưa vào đối với mỗi hàng
276            được truy xuất.
277        </td>
278    </tr>
279    <tr>
280        <td align="center"><code>selection</code></td>
281        <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td>
282        <td><code>selection</code> quy định các tiêu chí để lựa chọn hàng.</td>
283    </tr>
284    <tr>
285        <td align="center"><code>selectionArgs</code></td>
286        <td align="center">
287            (Không có sự tương đương chính xác. Các tham đối lựa chọn sẽ thay thế các chỗ dành sẵn <code>?</code> trong
288            mệnh đề lựa chọn.)
289        </td>
290    </tr>
291    <tr>
292        <td align="center"><code>sortOrder</code></td>
293        <td align="center"><code>ORDER BY <em>col,col,...</em></code></td>
294        <td>
295            <code>sortOrder</code> quy định thứ tự các hàng xuất hiện trong
296            {@link android.database.Cursor} được trả về.
297        </td>
298    </tr>
299</table>
300<h3 id="ContentURIs">URI Nội dung</h3>
301<p>
302    <strong>URI nội dung</strong> là một URI xác định dữ liệu trong một trình cung cấp. URI nội dung
303    bao gồm tên biểu tượng của toàn bộ trình cung cấp (<strong>quyền</strong> của nó) và một
304    tên trỏ đến một bảng (<strong>đường dẫn</strong>). Khi bạn gọi
305    một phương pháp máy khách để truy cập một bảng trong một trình cung cấp, URI nội dung cho bảng là một trong các
306    tham đối.
307</p>
308<p>
309    Trong các dòng mã trước, hằng số
310    {@link android.provider.UserDictionary.Words#CONTENT_URI} chứa URI nội dung của
311    bảng "từ" của từ điển người dùng. Đối tượng {@link android.content.ContentResolver}
312    sẽ phân tích quyền của URI, và sử dụng nó để "giải quyết" trình cung cấp bằng cách
313    so sánh quyền với một bảng hệ thống của các trình cung cấp đã biết. Khi đó,
314    {@link android.content.ContentResolver} có thể phân phối các tham đối truy vấn tới đúng
315    trình cung cấp.
316</p>
317<p>
318    {@link android.content.ContentProvider} sử dụng phần đường dẫn của URI nội dung nhằm chọn
319    bảng để truy cập. Trình cung cấp thường có một <strong>đường dẫn</strong> cho mỗi bảng mà nó hiện ra.
320</p>
321<p>
322    Trong các dòng mã trước, URI đầy đủ cho bảng "từ" là:
323</p>
324<pre>
325content://user_dictionary/words
326</pre>
327<p>
328    trong đó xâu <code>user_dictionary</code> là quyền của trình cung cấp, và
329xâu    <code>words</code> là đường dẫn của bảng. Xâu
330    <code>content://</code> (<strong>lược đồ</strong>) sẽ luôn có mặt,
331   và xác định đây là một URI nội dung.
332</p>
333<p>
334    Nhiều trình cung cấp cho phép bạn truy cập một hàng đơn lẻ trong một bảng bằng cách nối một giá trị ID
335    với đuôi của URI. Ví dụ, để truy xuất một hàng có <code>_ID</code> là
336    <code>4</code> từ một từ điển người dùng, bạn có thể sử dụng URI nội dung này:
337</p>
338<pre>
339Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
340</pre>
341<p>
342    Bạn thường sử dụng các giá trị id khi bạn đã truy xuất một tập hợp các hàng, sau đó muốn cập nhật hoặc xóa
343    một trong số chúng.
344</p>
345<p class="note">
346    <strong>Lưu ý:</strong> Các lớp {@link android.net.Uri} và {@link android.net.Uri.Builder}
347    chứa các phương pháp thuận tiện để xây dựng đối tượng URI định dạng tốt từ các xâu.
348    {@link android.content.ContentUris} chứa các phương pháp thuận tiện để nối các giá trị id với
349    một URI. Đoạn mã HTML trước sử dụng {@link android.content.ContentUris#withAppendedId
350withAppendedId()} để nối một id với URI nội dung Từ điển Người dùng.
351</p>
352
353
354    <!-- Retrieving Data from the Provider -->
355<h2 id="SimpleQuery">Truy xuất Dữ liệu từ Trình cung cấp</h2>
356<p>
357    Phần này mô tả cách truy xuất dữ liệu từ một trình cung cấp bằng cách sử dụng Trình cung cấp Từ điển Người dùng
358    làm ví dụ.
359</p>
360<p class="note">
361    Để giải thích rõ, đoạn mã HTML trong phần này gọi
362    {@link android.content.ContentResolver#query ContentResolver.query()} trên "luồng UI"". Tuy nhiên, trong
363    mã thực sự, bạn nên thực hiện các truy vấn không đồng bộ trên một luồng riêng. Một cách để làm
364    điều này đó là sử dụng lớp {@link android.content.CursorLoader}, nó được mô tả chi tiết hơn
365    trong hướng dẫn <a href="{@docRoot}guide/components/loaders.html">
366    Trình tải</a>. Bênh cạnh đó, các dòng mã chỉ là đoạn mã HTML; chúng không thể hiện một ứng dụng
367    hoàn chỉnh.
368</p>
369<p>
370    Để truy xuất dữ liệu từ một trình cung cấp, hãy làm theo các bước cơ bản sau:
371</p>
372<ol>
373   <li>
374        Yêu cầu quyền truy cập đọc cho trình cung cấp.
375   </li>
376   <li>
377        Định nghĩa mã để gửi một truy vấn tới trình cung cấp.
378   </li>
379</ol>
380<h3 id="RequestPermissions">Yêu cầu quyền truy cập đọc</h3>
381<p>
382    Để truy xuất dữ liệu từ một trình cung cấp, ứng dụng của bạn cần "quyền truy cập đọc" cho
383    trình cung cấp. Bạn không thể yêu cầu quyền này trong thời gian chạy; thay vào đó, bạn phải chỉ định rằng
384    bạn cần quyền này trong bản kê khai của mình bằng cách sử dụng phần tử
385<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
386    và tên quyền chính xác được định nghĩa bởi
387    trình cung cấp. Khi bạn chỉ định phần tử này trong bản kê khai của mình, bạn đang thực tế hóa "yêu cầu" quyền
388    này cho ứng dụng của mình. Khi người dùng cài đặt ứng dụng của bạn, họ ngầm hiểu cấp
389    yêu cầu này.
390</p>
391<p>
392    Để tìm tên chính xác của quyền truy cập đọc cho trình cung cấp bạn đang sử dụng, cũng như
393    tên cho các quyền truy cập khác được sử dụng bởi trình truy cập, hãy xem trong tài liệu
394    của trình cung cấp.
395</p>
396<p>
397    Vai trò của quyền trong việc truy cập các trình cung cấp được mô tả chi tiết hơn trong phần
398    <a href="#Permissions">Quyền của Trình cung cấp Nội dung</a>.
399</p>
400<p>
401    Trình cung cấp Từ điển Người dùng sẽ định nghĩa quyền
402    <code>android.permission.READ_USER_DICTIONARY</code> trong tệp bản kê khai của nó, vì vậy một
403    ứng dụng muốn đọc từ trình cung cấp sẽ phải yêu cầu quyền này.
404</p>
405<!-- Constructing the query -->
406<h3 id="Query">Xây dựng truy vấn</h3>
407<p>
408    Bước tiếp theo trong việc truy xuất dữ liệu từ một trình cung cấp đó là xây dựng một truy vấn. Đoạn mã HTML đầu tiên
409    này định nghĩa một số biến cho việc truy cập Trình cung cấp Từ điển Người dùng:
410</p>
411<pre class="prettyprint">
412
413// A "projection" defines the columns that will be returned for each row
414String[] mProjection =
415{
416    UserDictionary.Words._ID,    // Contract class constant for the _ID column name
417    UserDictionary.Words.WORD,   // Contract class constant for the word column name
418    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
419};
420
421// Defines a string to contain the selection clause
422String mSelectionClause = null;
423
424// Initializes an array to contain selection arguments
425String[] mSelectionArgs = {""};
426
427</pre>
428<p>
429    Đoạn mã HTML tiếp theo cho biết cách sử dụng
430    {@link android.content.ContentResolver#query ContentResolver.query()}, bằng cách sử dụng Trình cung cấp Từ điển
431    Người dùng như một ví dụ. Truy vấn máy khách trình cung cấp tương tự như một truy vấn SQL, và nó chứa một
432    tập hợp các cột để trả về, một tập hợp các tiêu chí lựa chọn, và một thứ tự sắp xếp.
433</p>
434<p>
435    Tập hợp các cột mà truy vấn cần trả về được gọi là <strong>dự thảo</strong>
436    (biến <code>mProjection</code>).
437</p>
438<p>
439    Biểu thức để chỉ định các hàng cần truy xuất sẽ được chia thành một mệnh đề lựa chọn và
440    tham đối lựa chọn. Mệnh đề lựa chọn là sự kết hợp giữa các biểu thức lô-gic và biểu thức Boolean,
441    tên cột, và giá trị (biến <code>mSelectionClause</code>). Nếu bạn chỉ định
442    tham số thay thế được <code>?</code> thay vì một giá trị, phương pháp truy vấn sẽ truy xuất giá trị
443    từ mảng tham đối lựa chọn (biến <code>mSelectionArgs</code>).
444</p>
445<p>
446    Trong đoạn mã HTML tiếp theo, nếu người dùng không điền từ thì mệnh đề lựa chọn được đặt thành
447    <code>null</code>, và truy vấn trả về tất cả các từ trong trình cung cấp. Nếu người dùng nhập
448    một từ, mệnh đề lựa chọn được đặt thành <code>UserDictionary.Words.WORD + " = ?"</code> và
449    phần tử đầu tiên của mảng tham đối lựa chọn được đặt thành từ mà người dùng đã nhập.
450</p>
451<pre class="prettyprint">
452/*
453 * This defines a one-element String array to contain the selection argument.
454 */
455String[] mSelectionArgs = {""};
456
457// Gets a word from the UI
458mSearchString = mSearchWord.getText().toString();
459
460// Remember to insert code here to check for invalid or malicious input.
461
462// If the word is the empty string, gets everything
463if (TextUtils.isEmpty(mSearchString)) {
464    // Setting the selection clause to null will return all words
465    mSelectionClause = null;
466    mSelectionArgs[0] = "";
467
468} else {
469    // Constructs a selection clause that matches the word that the user entered.
470    mSelectionClause = UserDictionary.Words.WORD + " = ?";
471
472    // Moves the user's input string to the selection arguments.
473    mSelectionArgs[0] = mSearchString;
474
475}
476
477// Does a query against the table and returns a Cursor object
478mCursor = getContentResolver().query(
479    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
480    mProjection,                       // The columns to return for each row
481    mSelectionClause                   // Either null, or the word the user entered
482    mSelectionArgs,                    // Either empty, or the string the user entered
483    mSortOrder);                       // The sort order for the returned rows
484
485// Some providers return null if an error occurs, others throw an exception
486if (null == mCursor) {
487    /*
488     * Insert code here to handle the error. Be sure not to use the cursor! You may want to
489     * call android.util.Log.e() to log this error.
490     *
491     */
492// If the Cursor is empty, the provider found no matches
493} else if (mCursor.getCount() &lt; 1) {
494
495    /*
496     * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily
497     * an error. You may want to offer the user the option to insert a new row, or re-type the
498     * search term.
499     */
500
501} else {
502    // Insert code here to do something with the results
503
504}
505</pre>
506<p>
507    Truy vấn này tương tự như câu lệnh SQL:
508</p>
509<pre>
510SELECT _ID, word, locale FROM words WHERE word = &lt;userinput&gt; ORDER BY word ASC;
511</pre>
512<p>
513    Trong câu lệnh SQL này, tên cột thực tế được sử dụng thay vì các hằng số lớp hợp đồng.
514</p>
515<h4 id="Injection">Bảo vệ trước mục nhập độc hại</h4>
516<p>
517    Nếu dữ liệu được quản lý bởi trình cung cấp nội dung nằm trong một cơ sở dữ liệu SQL, việc điền dữ liệu không được tin cậy từ bên ngoài
518    vào các câu lệnh SQL thô có thể dẫn đến tiêm lỗi SQL.
519</p>
520<p>
521    Hãy xét mệnh đề lựa chọn sau:
522</p>
523<pre>
524// Constructs a selection clause by concatenating the user's input to the column name
525String mSelectionClause =  "var = " + mUserInput;
526</pre>
527<p>
528    Nếu bạn làm vậy, bạn đang cho phép người dùng ghép nối SQL độc hại lên câu lệnh SQL của mình.
529    Ví dụ, người dùng có thể điền "nothing; DROP TABLE *;" cho <code>mUserInput</code>, làm vậy
530    sẽ dẫn đến mệnh đề lựa chọn <code>var = nothing; DROP TABLE *;</code>. Do
531    mệnh đề lựa chọn được coi như một câu lệnh SQL, điều này có thể khiến trình cung cấp xóa tất cả
532    bảng trong cơ sở dữ liệu SQLite cơ bản (trừ khi trình cung cấp được thiết lập để bắt những lần thử
533    <a href="http://en.wikipedia.org/wiki/SQL_injection">tiêm lỗi SQL</a>).
534</p>
535<p>
536    Để tránh vấn đề này, hãy sử dụng một mệnh đề lựa chọn mà sử dụng <code>?</code> làm tham số
537    thay thế được và một mảng các tham đối lựa chọn riêng. Khi bạn làm như vậy, mục nhập của người dùng
538    được gắn kết trực tiếp với truy vấn thay vì được giải nghĩa như một phần của câu lệnh SQL.
539    Vì nó không được coi như SQL, mục nhập của người dùng không thể tiêm lỗi SQL độc hại. Thay vì sử dụng
540    ghép nối để điền mục nhập của người dùng, hãy sử dụng mệnh đề lựa chọn này:
541</p>
542<pre>
543// Constructs a selection clause with a replaceable parameter
544String mSelectionClause =  "var = ?";
545</pre>
546<p>
547    Thiết lập mảng các tham đối lựa chọn như sau:
548</p>
549<pre>
550// Defines an array to contain the selection arguments
551String[] selectionArgs = {""};
552</pre>
553<p>
554    Đặt một giá trị trong mảng các tham đối lựa chọn như sau:
555</p>
556<pre>
557// Sets the selection argument to the user's input
558selectionArgs[0] = mUserInput;
559</pre>
560<p>
561    Mệnh đề lựa chọn mà sử dụng <code>?</code> như một tham số thay thế được và một mảng
562    các tham đối lựa chọn là cách được ưu tiên để chỉ định một lựa chọn, ngay cả khi trình cung cấp không
563    được dựa trên cơ sở dữ liệu SQL.
564</p>
565<!-- Displaying the results -->
566<h3 id="DisplayResults">Hiển thị các kết quả truy vấn</h3>
567<p>
568    Phương pháp máy khách {@link android.content.ContentResolver#query ContentResolver.query()} luôn trả về
569    một {@link android.database.Cursor} chứa các cột được chỉ định bởi dự thảo của
570    truy vấn cho các hàng khớp với các tiêu chí lựa chọn của truy vấn. Một đối tượng
571    {@link android.database.Cursor} cung cấp truy cập đọc ngẫu nhiên vào các hàng và cột mà nó
572    chứa. Bằng cách sử dụng phương pháp {@link android.database.Cursor}, bạn có thể lặp lại các hàng trong
573    kết quả, xác định kiểu dữ liệu của từng cột, lấy dữ liệu ra khỏi cột, và kiểm tra các tính chất khác
574    của kết quả. Một số triển khai {@link android.database.Cursor} sẽ tự động
575    cập nhật đối tượng khi dữ liệu của trình cung cấp thay đổi, hoặc kích khởi các phương pháp trong một đối tượng quan sát
576    khi {@link android.database.Cursor} thay đổi, hoặc cả hai.
577</p>
578<p class="note">
579    <strong>Lưu ý:</strong> Một trình cung cấp có thể hạn chế truy cập vào các cột dựa trên tính chất của
580    đối tượng thực hiện truy vấn. Ví dụ, Trình cung cấp Danh bạ hạn chế truy cập đối với một số cột cho
581    các trình điều hợp đồng bộ, vì thế nó sẽ không trả chúng về một hoạt động hay dịch vụ.
582</p>
583<p>
584    Nếu không hàng nào khớp với các tiêu chí lựa chọn, trình cung cấp
585    sẽ trả về một đối tượng {@link android.database.Cursor} mà trong đó
586    {@link android.database.Cursor#getCount Cursor.getCount()} bằng 0 (con chạy trống).
587</p>
588<p>
589    Nếu xảy ra một lỗi nội bộ, các kết quả của truy vấn sẽ phụ thuộc vào trình cung cấp cụ thể. Nó có thể
590    chọn trả về <code>null</code>, hoặc nó có thể đưa ra một lỗi {@link java.lang.Exception}.
591</p>
592<p>
593    Do {@link android.database.Cursor} là một "danh sách" hàng, một cách hay để hiển thị
594    nội dung của một {@link android.database.Cursor} đó là liên kết nó với một {@link android.widget.ListView}
595    thông qua một {@link android.widget.SimpleCursorAdapter}.
596</p>
597<p>
598    Đoạn mã HTML sau tiếp tục từ đoạn mã HTML trước. Nó tạo một đối tượng
599    {@link android.widget.SimpleCursorAdapter} chứa {@link android.database.Cursor}
600    được truy xuất bởi truy vấn, và đặt đối tượng này thành trình điều hợp cho một
601    {@link android.widget.ListView}:
602</p>
603<pre class="prettyprint">
604// Defines a list of columns to retrieve from the Cursor and load into an output row
605String[] mWordListColumns =
606{
607    UserDictionary.Words.WORD,   // Contract class constant containing the word column name
608    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
609};
610
611// Defines a list of View IDs that will receive the Cursor columns for each row
612int[] mWordListItems = { R.id.dictWord, R.id.locale};
613
614// Creates a new SimpleCursorAdapter
615mCursorAdapter = new SimpleCursorAdapter(
616    getApplicationContext(),               // The application's Context object
617    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
618    mCursor,                               // The result from the query
619    mWordListColumns,                      // A string array of column names in the cursor
620    mWordListItems,                        // An integer array of view IDs in the row layout
621    0);                                    // Flags (usually none are needed)
622
623// Sets the adapter for the ListView
624mWordList.setAdapter(mCursorAdapter);
625</pre>
626<p class="note">
627    <strong>Lưu ý:</strong> Để lùi {@link android.widget.ListView} bằng một
628    {@link android.database.Cursor}, con chạy phải chứa một cột có tên <code>_ID</code>.
629    Vì điều này, truy vấn được hiện lúc trước truy xuất cột <code>_ID</code> cho
630    bảng "từ" mặc dù {@link android.widget.ListView} không hiển thị nó.
631    Hạn chế này cũng giải thích lý do tại sao phần lớn trình cung cấp đều có một cột <code>_ID</code> cho mỗi
632    bảng của nó.
633</p>
634
635        <!-- Getting data from query results -->
636<h3 id="GettingResults">Lấy dữ liệu từ các kết quả truy vấn</h3>
637<p>
638    Thay vì chỉ hiển thị các kết quả truy vấn, bạn có thể sử dụng chúng cho các tác vụ khác. Ví
639    dụ, bạn có thể truy xuất chính tả từ một từ điển người dùng, rồi sau đó tìm kiếm từ đó trong
640    các trình cung cấp khác. Để làm điều này, bạn lặp lại các hàng trong {@link android.database.Cursor}:
641</p>
642<pre class="prettyprint">
643
644// Determine the column index of the column named "word"
645int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);
646
647/*
648 * Only executes if the cursor is valid. The User Dictionary Provider returns null if
649 * an internal error occurs. Other providers may throw an Exception instead of returning null.
650 */
651
652if (mCursor != null) {
653    /*
654     * Moves to the next row in the cursor. Before the first movement in the cursor, the
655     * "row pointer" is -1, and if you try to retrieve data at that position you will get an
656     * exception.
657     */
658    while (mCursor.moveToNext()) {
659
660        // Gets the value from the column.
661        newWord = mCursor.getString(index);
662
663        // Insert code here to process the retrieved word.
664
665        ...
666
667        // end of while loop
668    }
669} else {
670
671    // Insert code here to report an error if the cursor is null or the provider threw an exception.
672}
673</pre>
674<p>
675    Triển khai {@link android.database.Cursor} sẽ chứa một vài phương pháp “get" để
676    truy xuất các kiểu dữ liệu khác nhau từ đối tượng. Ví dụ, đoạn mã HTML trước
677    sử dụng {@link android.database.Cursor#getString getString()}. Chúng cũng có một phương pháp
678    {@link android.database.Cursor#getType getType()} để trả về một giá trị cho biết
679    kiểu dữ liệu của cột.
680</p>
681
682
683    <!-- Requesting permissions -->
684<h2 id="Permissions">Quyền của Trình cung cấp Nội dung</h2>
685<p>
686    Ứng dụng của một trình cung cấp có thể chỉ định các quyền mà ứng dụng khác có thể có để
687    truy cập dữ liệu của trình cung cấp đó. Những quyền này đảm bảo rằng người dùng biết một ứng dụng
688    sẽ cố gắng truy cập dữ liệu nào. Dựa trên các yêu cầu của trình cung cấp, các ứng dụng khác
689    yêu cầu quyền mà chúng cần để truy cập trình dữ liệu. Người dùng cuối thấy các quyền
690    được yêu cầu khi họ cài đặt ứng dụng.
691</p>
692<p>
693    Nếu ứng dụng của một trình cung cấp không chỉ định bất kỳ quyền nào, khi đó các ứng dụng khác không có
694    quyền truy cập dữ liệu của trình cung cấp. Tuy nhiên, các thành phần trong ứng dụng của trình cung cấp luôn có
695    đầy đủ quyền truy nhập đọc và ghi, không phụ thuộc vào các quyền được chỉ định.
696</p>
697<p>
698    Như đã lưu ý, Trình cung cấp Từ điển Người dùng sẽ yêu cầu
699    quyền <code>android.permission.READ_USER_DICTIONARY</code> để truy xuất dữ liệu từ nó.
700    Trình cung cấp có quyền <code>android.permission.WRITE_USER_DICTIONARY</code>
701    riêng để chèn, cập nhật, hoặc xóa dữ liệu.
702</p>
703<p>
704    Để nhận các quyền cần để truy cập một trình cung cấp, ứng dụng yêu cầu chúng bằng một phần tử
705<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
706    trong tệp bản kê khai của nó. Khi Trình quản lý Gói Android cài đặt các ứng dụng, người dùng
707    phải phê chuẩn tất cả quyền mà ứng dụng yêu cầu. Nếu người dùng phê chuẩn tất cả quyền, khi đó
708    Trình quản lý Gói sẽ tiếp tục cài đặt; nếu người dùng không phê chuẩn chúng, Trình quản lý Gói sẽ
709    hủy bỏ việc cài đặt.
710</p>
711<p>
712    Phần tử
713<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
714    sau yêu cầu quyền truy cập đọc vào Trình cung cấp Từ điển Người dùng:
715</p>
716<pre>
717    &lt;uses-permission android:name="android.permission.READ_USER_DICTIONARY"&gt;
718</pre>
719<p>
720    Tác động của các quyền tới việc truy cập trình cung cấp được giải thích chi tiết hơn trong
721    hướng dẫn <a href="{@docRoot}guide/topics/security/security.html">Bảo mật và Quyền</a>.
722</p>
723
724
725<!-- Inserting, Updating, and Deleting Data -->
726<h2 id="Modifications">Chèn, Cập nhật, và Xóa Dữ liệu</h2>
727<p>
728    Giống như cách bạn truy xuất dữ liệu từ một trình cung cấp, bạn cũng có thể sử dụng tương tác giữa
729    một máy khách cung cấp và {@link android.content.ContentProvider} của trình cung cấp để sửa đổi dữ liệu.
730    Bạn gọi một phương pháp {@link android.content.ContentResolver} với các tham đối được chuyển sang
731    phương pháp {@link android.content.ContentProvider} tương ứng. Trình cung cấp và
732    máy khách cung cấp sẽ tự động xử lý bảo mật và truyền thông liên tiến trình.
733</p>
734<h3 id="Inserting">Chèn dữ liệu</h3>
735<p>
736    Để chèn dữ liệu vào một trình cung cấp, bạn gọi phương pháp
737    {@link android.content.ContentResolver#insert ContentResolver.insert()}
738. Phương pháp này chèn một hàng mới vào trình cung cấp và trả về một URI nội dung cho hàng đó.
739    Đoạn mã HTML này cho biết cách chèn một từ mới vào Trình cung cấp Từ điển Người dùng:
740</p>
741<pre class="prettyprint">
742// Defines a new Uri object that receives the result of the insertion
743Uri mNewUri;
744
745...
746
747// Defines an object to contain the new values to insert
748ContentValues mNewValues = new ContentValues();
749
750/*
751 * Sets the values of each column and inserts the word. The arguments to the "put"
752 * method are "column name" and "value"
753 */
754mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
755mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
756mNewValues.put(UserDictionary.Words.WORD, "insert");
757mNewValues.put(UserDictionary.Words.FREQUENCY, "100");
758
759mNewUri = getContentResolver().insert(
760    UserDictionary.Word.CONTENT_URI,   // the user dictionary content URI
761    mNewValues                          // the values to insert
762);
763</pre>
764<p>
765    Dữ liệu cho hàng mới đi vào trong một đối tượng {@link android.content.ContentValues} đơn lẻ, đối tượng này
766    có dạng tương tự như con chạy một hàng. Các cột trong đối tượng này không cần có
767    cùng kiểu dữ liệu, và nếu hoàn toàn không muốn chỉ định một giá trị, bạn có thể đặt một cột
768    thành <code>null</code> bằng cách sử dụng {@link android.content.ContentValues#putNull ContentValues.putNull()}.
769</p>
770<p>
771    Đoạn mã HTML không thêm cột <code>_ID</code> vì cột này được tự động
772    duy trì. Trình cung cấp sẽ gán một giá trị duy nhất <code>_ID</code> cho mỗi hàng được
773    thêm. Các trình cung cấp thường sử dụng giá trị này làm khóa chính của bảng.
774</p>
775<p>
776    URI nội dung được trả về trong <code>newUri</code> sẽ xác định hàng mới thêm, có
777    định dạng như sau:
778</p>
779<pre>
780content://user_dictionary/words/&lt;id_value&gt;
781</pre>
782<p>
783    <code>&lt;id_value&gt;</code> là nội dung của <code>_ID</code> cho hàng mới.
784    Hầu hết các trình cung cấp đều có thể tự động phát hiện dạng URI nội dung này rồi thực hiện thao tác được yêu cầu
785    trên hàng cụ thể đó.
786</p>
787<p>
788    Để nhận giá trị <code>_ID</code> từ {@link android.net.Uri} được trả về, hãy gọi
789    {@link android.content.ContentUris#parseId ContentUris.parseId()}.
790</p>
791<h3 id="Updating">Cập nhật dữ liệu</h3>
792<p>
793    Để cập nhật một hàng, bạn sử dụng một đối tượng {@link android.content.ContentValues} với các giá trị
794    được cập nhật giống như cách bạn làm với việc chèn, và các tiêu chí lựa chọn giống như cách bạn làm với truy vấn.
795    Phương pháp máy khách mà bạn sử dụng là
796    {@link android.content.ContentResolver#update ContentResolver.update()}. Bạn chỉ cần thêm
797    các giá trị vào đối tượng {@link android.content.ContentValues} cho các cột mà bạn đang cập nhật. Nếu bạn
798    muốn xóa các nội dung của một cột, hãy đặt giá trị thành <code>null</code>.
799</p>
800<p>
801    Đoạn mã HTML sau thay đổi tất cả hàng với cột bản địa có ngôn ngữ "en" thành cột
802    có bản địa là <code>null</code>. Giá trị trả về là số hàng đã được cập nhật:
803</p>
804<pre>
805// Defines an object to contain the updated values
806ContentValues mUpdateValues = new ContentValues();
807
808// Defines selection criteria for the rows you want to update
809String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";
810String[] mSelectionArgs = {"en_%"};
811
812// Defines a variable to contain the number of updated rows
813int mRowsUpdated = 0;
814
815...
816
817/*
818 * Sets the updated value and updates the selected words.
819 */
820mUpdateValues.putNull(UserDictionary.Words.LOCALE);
821
822mRowsUpdated = getContentResolver().update(
823    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
824    mUpdateValues                       // the columns to update
825    mSelectionClause                    // the column to select on
826    mSelectionArgs                      // the value to compare to
827);
828</pre>
829<p>
830    Bạn cũng nên thanh lọc thông tin đầu vào của người dùng khi gọi
831    {@link android.content.ContentResolver#update ContentResolver.update()}. Để tìm hiểu thêm về
832    điều này, hãy đọc phần <a href="#Injection">Bảo vệ trước mục nhập độc hại</a>.
833</p>
834<h3 id="Deleting">Xóa dữ liệu</h3>
835<p>
836    Xóa hàng tương tự như truy xuất dữ liệu hàng: bạn chỉ định các tiêu chí lựa chọn cho hàng
837    mà bạn muốn xóa và phương pháp máy khách trả về số hàng được xóa.
838    Đoạn mã HTML sau xóa các hàng có appid khớp với "user". Phương pháp sẽ trả về
839    số hàng được xóa.
840</p>
841<pre>
842
843// Defines selection criteria for the rows you want to delete
844String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
845String[] mSelectionArgs = {"user"};
846
847// Defines a variable to contain the number of rows deleted
848int mRowsDeleted = 0;
849
850...
851
852// Deletes the words that match the selection criteria
853mRowsDeleted = getContentResolver().delete(
854    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
855    mSelectionClause                    // the column to select on
856    mSelectionArgs                      // the value to compare to
857);
858</pre>
859<p>
860    Bạn cũng nên thanh lọc thông tin đầu vào của người dùng khi gọi
861    {@link android.content.ContentResolver#delete ContentResolver.delete()}. Để tìm hiểu thêm về
862    điều này, hãy đọc phần <a href="#Injection">Bảo vệ trước mục nhập độc hại</a>.
863</p>
864<!-- Provider Data Types -->
865<h2 id="DataTypes">Các Kiểu Dữ liệu của Trình cung cấp</h2>
866<p>
867    Trình cung cấp nội dung có thể cung cấp nhiều kiểu dữ liệu khác nhau. Trình cung cấp Từ điển Người dùng chỉ cung cấp
868    văn bản, nhưng trình cung cấp cũng có thể cung cấp các định dạng sau:
869</p>
870    <ul>
871        <li>
872            integer
873        </li>
874        <li>
875            long integer (long)
876        </li>
877        <li>
878            floating point
879        </li>
880        <li>
881            long floating point (double)
882        </li>
883    </ul>
884<p>
885    Một kiểu dữ liệu khác mà các trình cung cấp thường sử dụng đó là Binary Large OBject (BLOB) được triển khai như một
886    mảng 64KB byte. Bạn có thể xem các kiểu dữ liệu có sẵn bằng cách xem các phương pháp "get" lớp
887    {@link android.database.Cursor}.
888</p>
889<p>
890    Kiểu dữ liệu đối với mỗi cột trong một trình cung cấp thường được liệt kê trong tài liệu của trình cung cấp đó.
891    Các kiểu dữ liệu dành cho Trình cung cấp Từ điển Người dùng được liệt kê trong tài liệu tham khảo
892    cho lớp hợp đồng {@link android.provider.UserDictionary.Words} của nó (lớp hợp đồng được
893    mô tả trong phần <a href="#ContractClasses">Các Lớp Hợp đồng</a>).
894    Bạn cũng có thể xác định kiểu dữ liệu bằng cách gọi {@link android.database.Cursor#getType
895    Cursor.getType()}.
896</p>
897<p>
898    Trình cung cấp cũng duy trì thông tin về kiểu dữ liệu MIME cho mỗi URI nội dung mà chúng định nghĩa. Bạn có thể
899    sử dụng thông tin về kiểu MIME để tìm hiểu xem ứng dụng của mình có thể xử lý dữ liệu mà
900    trình cung cấp đưa ra hay không, hoặc để chọn một kiểu xử lý dựa trên kiểu MIME. Bạn thường cần kiểu
901    MIME khi đang làm việc với một trình cung cấp chứa các cấu trúc hoặc tệp
902    dữ liệu phức tạp. Ví dụ, bảng {@link android.provider.ContactsContract.Data}
903    trong Trình cung cấp Danh bạ sử dụng các kiểu MIME để dán nhãn kiểu dữ liệu liên lạc được lưu trữ trong từng
904    hàng. Để nhận được kiểu MIME tương ứng với một URI nội dung, hãy gọi
905    {@link android.content.ContentResolver#getType ContentResolver.getType()}.
906</p>
907<p>
908    Phần <a href="#MIMETypeReference">Tham khảo Kiểu MIME</a> mô tả
909    cú pháp của cả kiểu MIME tiêu chuẩn lẫn tùy chỉnh.
910</p>
911
912
913<!-- Alternative Forms of Provider Access -->
914<h2 id="AltForms">Các Hình thức Truy cập Trình cung cấp Thay thế</h2>
915<p>
916    Có ba hình thức truy cập trình cung cấp thay thế quan trọng trong phát triển ứng dụng:
917</p>
918<ul>
919    <li>
920        <a href="#Batch">Truy cập hàng loạt</a>: Bạn có thể tạo một loạt lệnh gọi truy cập bằng các phương pháp trong
921        lớp {@link android.content.ContentProviderOperation}, rồi sau đó áp dụng chúng với
922        {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}.
923    </li>
924    <li>
925        Truy vấn không đồng bộ: Bạn nên thực hiện các truy vấn trong một luồng riêng. Một cách để làm điều này đó là
926        sử dụng một đối tượng {@link android.content.CursorLoader}. Các ví dụ trong
927        hướng dẫn <a href="{@docRoot}guide/components/loaders.html">Trình tải</a> sẽ minh họa
928        cách làm điều này.
929    </li>
930    <li>
931        <a href="#Intents">Truy cập dữ liệu thông qua ý định</a>: Mặc dù không thể gửi một ý định
932        trực tiếp tới một trình cung cấp, bạn có thể gửi một ý định tới ứng dụng của trình cung cấp đó,
933        đây thường là cách tốt nhất để sửa đổi dữ liệu của trình cung cấp.
934    </li>
935</ul>
936<p>
937    Truy cập hàng loạt và sửa đổi thông qua ý định được mô tả trong các phần sau.
938</p>
939<h3 id="Batch">Truy cập hàng loạt</h3>
940<p>
941    Truy cập hàng loạt vào một trình cung cấp là cách hữu ích để chèn nhiều hàng, hoặc để chèn
942    các hàng vào nhiều bảng trong cùng lệnh gọi phương pháp, hoặc nhìn chung để thực hiện một tập hợp
943    thao tác qua các ranh giới tiến trình như một giao tác (thao tác nguyên tử).
944</p>
945<p>
946    Để truy cập một trình cung cấp trong "chế độ hàng loạt",
947    bạn tạo một mảng đối tượng {@link android.content.ContentProviderOperation} rồi
948    phân phối chúng tới một trình cung cấp nội dung bằng
949    {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. Bạn chuyển
950    <em>quyền</em> của trình cung cấp nội dung cho phương pháp này thay vì một URI nội dung cụ thể.
951Điều này cho phép đối tượng {@link android.content.ContentProviderOperation} trong mảng có tác dụng
952    đối với một bảng khác. Một lệnh gọi tới {@link android.content.ContentResolver#applyBatch
953    ContentResolver.applyBatch()} trả về một mảng kết quả.
954</p>
955<p>
956    Mô tả lớp hợp đồng {@link android.provider.ContactsContract.RawContacts}
957    bao gồm một đoạn mã HTML thể hiện việc chèn hàng loạt. Ứng dụng mẫu
958    <a href="{@docRoot}resources/samples/ContactManager/index.html">Trình quản lý Danh bạ</a>
959    có một ví dụ về truy cập hàng loạt trong tệp nguồn <code>ContactAdder.java</code>
960    của nó.
961</p>
962<div class="sidebox-wrapper">
963<div class="sidebox">
964<h2>Hiển thị dữ liệu bằng cách sử dụng một ứng dụng trình trợ giúp.</h2>
965<p>
966    Nếu ứng dụng của bạn <em>có</em> quyền truy cập, bạn vẫn có thể cần sử dụng một
967    ý định để hiển thị dữ liệu trong một ứng dụng khác. Ví dụ, ứng dụng Lịch chấp nhận một
968    ý định {@link android.content.Intent#ACTION_VIEW}, nhằm hiển thị một ngày hoặc sự kiện cụ thể.
969    Điều này cho phép bạn hiển thị thông tin lịch mà không phải tạo UI của chính mình.
970    Để tìm hiểu thêm về tính năng này, hãy xem
971    hướng dẫn <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Trình cung cấp Lịch</a>.
972</p>
973<p>
974    Ứng dụng mà bạn gửi ý định đến không nhất thiết phải là ứng dụng
975    được liên kết với trình cung cấp. Ví dụ, bạn có thể truy xuất một liên lạc từ
976    Trình cung cấp Danh bạ, rồi gửi một ý định {@link android.content.Intent#ACTION_VIEW}
977    chứa URI nội dung cho hình ảnh liên lạc tới một trình xem ảnh.
978</p>
979</div>
980</div>
981<h3 id="Intents">Truy cập dữ liệu thông qua ý định</h3>
982<p>
983    Ý định có thể cho phép truy cập gián tiếp vào một trình cung cấp nội dung. Bạn cho phép người dùng truy cập
984    dữ liệu trong một trình cung cấp ngay cả khi ứng dụng của bạn không có quyền truy cập, hoặc bằng cách
985    nhận lại một ý định kết quả từ một ứng dụng có quyền, hoặc bằng cách kích hoạt một
986    ứng dụng có phép và cho phép người dùng được làm việc trong nó.
987</p>
988<h4>Được truy cập với các quyền tạm thời</h4>
989<p>
990    Bạn có thể truy cập dữ liệu trong một trình cung cấp nội dung, ngay cả khi bạn không có quyền
991    truy nhập phù hợp, bằng cách gửi một ý định tới một ứng dụng có quyền và
992    nhận lại một ý định kết quả chứa quyền "URI".
993    Đây là những quyền cho một URI nội dung cụ thể kéo dài tới khi hoạt động nhận chúng
994    được hoàn thành. Ứng dụng có quyền lâu dài sẽ cấp quyền tạm thời
995    bằng cách đặt một cờ trong ý định kết quả:
996</p>
997<ul>
998    <li>
999        <strong>Quyền đọc:</strong>
1000        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}
1001    </li>
1002    <li>
1003        <strong>Quyền ghi:</strong>
1004        {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}
1005    </li>
1006</ul>
1007<p class="note">
1008    <strong>Lưu ý:</strong> Những cờ này không cấp quyền truy cập đọc và ghi nói chung cho trình cung cấp
1009    mà có quyền được chứa trong URI nội dung. Quyền truy cập này chỉ áp dụng cho chính URI đó.
1010</p>
1011<p>
1012    Trình cung cấp sẽ định nghĩa quyền URI cho các URI nội dung trong bản kê khai của nó, bằng cách sử dụng thuộc tính
1013<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code>
1014    của phần tử
1015<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
1016    cũng như phần tử con
1017<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
1018    của phần tử
1019<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
1020    . Cơ chế cấp quyền URI này được giải thích chi tiết hơn trong
1021    hướng dẫn <a href="{@docRoot}guide/topics/security/security.html">Bảo mật và Quyền</a>,
1022    trong phần "Quyền URI".
1023</p>
1024<p>
1025    Ví dụ, bạn có thể truy xuất dữ liệu cho một liên lạc trong Trình cung cấp Danh bạ, ngay cả khi bạn không
1026    có quyền {@link android.Manifest.permission#READ_CONTACTS}. Bạn có thể muốn thực hiện điều này
1027    trong một ứng dụng gửi thiệp mừng điện tử tới một liên lạc vào ngày sinh nhật của người đó. Thay vì
1028    yêu cầu {@link android.Manifest.permission#READ_CONTACTS}, là nơi cấp cho bạn quyền truy cập tất cả liên lạc
1029    của người dùng và tất cả thông tin của họ, bạn nên cho phép người dùng kiểm soát những liên lạc
1030    nào được sử dụng bởi ứng dụng của bạn. Để làm điều này, bạn sử dụng tiến trình sau:
1031</p>
1032<ol>
1033    <li>
1034        Ứng dụng của bạn gửi một ý định chứa hành động
1035        {@link android.content.Intent#ACTION_PICK} và kiểu MIME "danh bạ"
1036{@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, bằng cách sử dụng
1037        phương pháp {@link android.app.Activity#startActivityForResult
1038        startActivityForResult()}.
1039    </li>
1040    <li>
1041        Vì ý định này khớp với bộ lọc ý định cho hoạt động
1042        "lựa chọn" của ứng dụng Danh bạ, hoạt động sẽ đi đến tiền cảnh.
1043    </li>
1044    <li>
1045        Trong hoạt động lựa chọn, người dùng chọn một
1046        liên lạc để cập nhật. Khi điều này xảy ra, hoạt động lựa chọn sẽ gọi
1047        {@link android.app.Activity#setResult setResult(resultcode, intent)}
1048        để thiết lập một ý định nhằm gửi lại ứng dụng của bạn. Ý định chứa URI nội dung
1049        của liên lạc mà người dùng đã chọn, và các cờ "phụ thêm"
1050        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. Những cờ này cấp quyền URI
1051        cho ứng dụng của bạn để đọc dữ liệu cho liên lạc được trỏ đến bởi
1052        URI nội dung. Sau đó, hoạt động lựa chọn gọi {@link android.app.Activity#finish()} để
1053        trả kiểm soát về ứng dụng của bạn.
1054    </li>
1055    <li>
1056        Hoạt động của bạn trả về tiền cảnh, và hệ thống sẽ gọi phương pháp
1057        {@link android.app.Activity#onActivityResult onActivityResult()}
1058        của hoạt động của bạn. Phương pháp này nhận được ý định kết quả do hoạt động lựa chọn tạo trong
1059        ứng dụng Danh bạ.
1060    </li>
1061    <li>
1062        Với URI nội dung từ ý định kết quả, bạn có thể đọc dữ liệu của liên lạc
1063        từ Trình cung cấp Danh bạ, ngay cả khi bạn không yêu cầu quyền truy cập đọc lâu dài
1064        vào trình cung cấp trong bản kê khai của mình. Sau đó, bạn có thể nhận thông tin ngày sinh của liên lạc
1065        hoặc địa chỉ e-mail của người đó rồi gửi thiệp mừng điện tử.
1066    </li>
1067</ol>
1068<h4>Sử dụng một ứng dụng khác</h4>
1069<p>
1070    Một cách đơn giản để cho phép người dùng sửa đổi dữ liệu mà bạn không có quyền truy cập đó là
1071    kích hoạt một ứng dụng có quyền và cho phép người dùng làm việc ở đó.
1072</p>
1073<p>
1074    Ví dụ, ứng dụng Lịch chấp nhận một
1075    ý định {@link android.content.Intent#ACTION_INSERT}, nó cho phép bạn kích hoạt UI chèn
1076    của ứng dụng. Bạn có thể chuyển dữ liệu "phụ thêm" trong ý định này mà được ứng dụng sử dụng
1077    để điền trước vào UI. Vì các sự kiện định kỳ có cú pháp phức tạp, cách
1078    ưu tiên để chèn sự kiện vào Trình cung cấp Lịch đó là kích hoạt ứng dụng Lịch với một
1079    {@link android.content.Intent#ACTION_INSERT} rồi để người dùng chèn sự kiện tại đó.
1080</p>
1081<!-- Contract Classes -->
1082<h2 id="ContractClasses">Các Lớp Hợp đồng</h2>
1083<p>
1084    Lớp hợp đồng định nghĩa các hằng số sẽ giúp ứng dụng hoạt động với các URI nội dung, tên
1085    cột, hành động ý định, và các tính năng khác của một trình cung cấp nội dung. Các lớp hợp đồng không
1086    được tự động đưa vào cùng một trình cung cấp; nhà phát triển của trình cung cấp phải định nghĩa chúng rồi
1087    cung cấp chúng cho các nhà phát triển khác. Nhiều trình cung cấp được bao gồm cùng với nền tảng
1088    Android có các lớp hợp đồng tương ứng trong gói {@link android.provider}.
1089</p>
1090<p>
1091    Ví dụ, Trình cung cấp Từ điển Người dùng có một lớp hợp đồng
1092    {@link android.provider.UserDictionary} chứa các hằng số URI nội dung và tên cột. URI nội dung
1093    đối với bảng "từ" được định nghĩa trong hằng số
1094    {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}.
1095    Lớp {@link android.provider.UserDictionary.Words} cũng chứa các hằng số tên cột,
1096    chúng được sử dụng trong đoạn mã HTML mẫu trong hướng dẫn này. Ví dụ, một dự thảo truy vấn có thể được
1097    định nghĩa là:
1098</p>
1099<pre>
1100String[] mProjection =
1101{
1102    UserDictionary.Words._ID,
1103    UserDictionary.Words.WORD,
1104    UserDictionary.Words.LOCALE
1105};
1106</pre>
1107<p>
1108    Một lớp hợp đồng khác là {@link android.provider.ContactsContract} dành cho Trình cung cấp Danh bạ.
1109    Tài liệu tham khảo cho lớp này bao gồm các đoạn mã HTML mẫu. Một trong số các
1110    lớp con của nó, {@link android.provider.ContactsContract.Intents.Insert}, là một lớp hợp đồng
1111    chứa các hằng số cho ý định và dữ liệu ý định.
1112</p>
1113
1114
1115<!-- MIME Type Reference -->
1116<h2 id="MIMETypeReference">Tham khảo Kiểu MIME</h2>
1117<p>
1118    Trình cung cấp nội dung có thể trả về các kiểu phương tiện MIME tiêu chuẩn, hoặc xâu kiểu MIME tùy chỉnh, hoặc cả hai.
1119</p>
1120<p>
1121    Các kiểu MIME có định dạng
1122</p>
1123<pre>
1124<em>type</em>/<em>subtype</em>
1125</pre>
1126<p>
1127    Ví dụ, kiểu MIME thông dụng <code>text/html</code> có kiểu <code>text</code> và
1128    kiểu con <code>html</code>. Nếu trình cung cấp trả về loại này cho một URI, điều đó có nghĩa rằng một
1129    truy vấn đang sử dụng URI đó sẽ trả về văn bản chứa thẻ HTML.
1130</p>
1131<p>
1132    Các xâu kiểu MIME tùy chỉnh, còn gọi là kiểu MIME "theo nhà cung cấp", có các giá trị
1133    <em>kiểu</em> và <em>kiểu con</em> phức tạp hơn. Giá trị <em>kiểu</em> luôn luôn
1134</p>
1135<pre>
1136vnd.android.cursor.<strong>dir</strong>
1137</pre>
1138<p>
1139    áp dụng cho nhiều hàng, hoặc
1140</p>
1141<pre>
1142vnd.android.cursor.<strong>item</strong>
1143</pre>
1144<p>
1145    áp dụng cho một hàng.
1146</p>
1147<p>
1148    Giá trị <em>kiểu con</em> áp dụng theo trình cung cấp. Các trình cung cấp được tích hợp trong Android thường có một kiểu con
1149    đơn giản. Ví dụ, khi ứng dụng Danh bạ tạo một hàng cho một số điện thoại,
1150    nó đặt kiểu MIME sau trong hàng:
1151</p>
1152<pre>
1153vnd.android.cursor.item/phone_v2
1154</pre>
1155<p>
1156    Để ý rằng giá trị kiểu con đơn giản là <code>phone_v2</code>.
1157</p>
1158<p>
1159    Các nhà phát triển trình cung cấp khác có thể tạo mẫu hình kiểu con của riêng mình dựa trên quyền
1160    và tên bảng của trình cung cấp. Ví dụ, xét một trình cung cấp chứa các biểu thời gian lịch tàu.
1161    Quyền của trình cung cấp là <code>com.example.trains</code>, và nó chứa các bảng
1162    Line1, Line2, và Line3. Để phản hồi lại URI nội dung
1163</p>
1164<p>
1165<pre>
1166content://com.example.trains/Line1
1167</pre>
1168<p>
1169    đối với bảng Line1, trình cung cấp trả về kiểu MIME
1170</p>
1171<pre>
1172vnd.android.cursor.<strong>dir</strong>/vnd.example.line1
1173</pre>
1174<p>
1175     Để phản hồi lại URI nội dung
1176</p>
1177<pre>
1178content://com.example.trains/Line2/5
1179</pre>
1180<p>
1181    đối với hàng 5 trong bảng Line2, trình cung cấp trả về kiểu MIME
1182</p>
1183<pre>
1184vnd.android.cursor.<strong>item</strong>/vnd.example.line2
1185</pre>
1186<p>
1187    Hầu hết các trình cung cấp nội dung đều định nghĩa hằng số lớp hợp đồng cho các kiểu MIME mà chúng sử dụng. Ví dụ như lớp hợp đồng
1188    của Trình cung cấp Danh bạ {@link android.provider.ContactsContract.RawContacts},
1189    sẽ định nghĩa hằng số
1190    {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} cho kiểu MIME của
1191    một hàng liên lạc thô duy nhất.
1192</p>
1193<p>
1194    Các URI nội dung đối với hàng duy nhất được mô tả trong phần
1195    <a href="#ContentURIs">URI nội dung</a>.
1196</p>
1197