1page.title=Dasar-Dasar Penyedia Konten
2@jd:body
3<div id="qv-wrapper">
4<div id="qv">
5<!-- In this document -->
6<h2>Dalam dokumen ini</h2>
7<ol>
8    <li>
9        <a href="#Basics">Ikhtisar</a>
10        <ol>
11            <li>
12                <a href="#ClientProvider">Mengakses penyedia</a>
13            </li>
14            <li>
15                <a href="#ContentURIs">URI Konten</a>
16            </li>
17        </ol>
18    </li>
19    <li>
20        <a href="#SimpleQuery">Mengambil Data dari Penyedia</a>
21        <ol>
22            <li>
23                <a href="#RequestPermissions">Meminta izin akses baca</a>
24            </li>
25            <li>
26                <a href="#Query">Membuat query</a>
27            </li>
28            <li>
29                <a href="#DisplayResults">Menampilkan hasil query</a>
30            </li>
31            <li>
32                <a href="#GettingResults">Mendapatkan data dari hasil query</a>
33            </li>
34        </ol>
35    </li>
36    <li>
37        <a href="#Permissions">Izin Penyedia Konten</a>
38    </li>
39    <li>
40        <a href="#Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</a>
41        <ol>
42            <li>
43                <a href="#Inserting">Menyisipkan data</a>
44            </li>
45            <li>
46                <a href="#Updating">Memperbarui data</a>
47            </li>
48            <li>
49                <a href="#Deleting">Menghapus data</a>
50            </li>
51        </ol>
52    </li>
53    <li>
54        <a href="#DataTypes">Tipe Data Penyedia</a>
55    </li>
56    <li>
57        <a href="#AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</a>
58        <ol>
59            <li>
60                <a href="#Batch">Akses batch</a>
61            </li>
62            <li>
63                <a href="#Intents">Akses data melalui intent</a>
64            </li>
65        </ol>
66    </li>
67    <li>
68        <a href="#ContractClasses">Kelas-kelas Kontrak</a>
69    </li>
70    <li>
71        <a href="#MIMETypeReference">Acuan Tipe MIME</a>
72    </li>
73</ol>
74
75    <!-- Key Classes -->
76<h2>Kelas-kelas utama</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>Contoh-Contoh Terkait</h2>
94    <ol>
95        <li>
96        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
97        Kursor (Orang)</a>
98        </li>
99        <li>
100        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
101        Kursor (Telepon)</a>
102        </li>
103    </ol>
104
105    <!-- See also -->
106<h2>Lihat juga</h2>
107    <ol>
108        <li>
109            <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
110            Membuat Penyedia Konten</a>
111        </li>
112        <li>
113            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
114            Penyedia Kalender</a>
115        </li>
116    </ol>
117</div>
118</div>
119
120    <!-- Intro paragraphs -->
121<p>
122    Penyedia konten mengelola akses ke repository data pusat. Penyedia
123    adalah bagian dari aplikasi Android, yang sering menyediakan UI-nya sendiri untuk menggunakan
124    data. Akan tetapi, penyedia konten terutama dimaksudkan untuk digunakan oleh
125    aplikasi lain, yang mengakses penyedia itu melalui objek klien penyedia. Bersama-sama, penyedia
126    dan klien penyedia menawarkan antarmuka standar yang konsisten ke data yang juga menangani
127    komunikasi antar-proses dan akses data aman.
128</p>
129<p>
130    Topik ini menerangkan dasar-dasar dari hal-hal berikut:
131</p>
132    <ul>
133        <li>Cara kerja penyedia konten.</li>
134        <li>API yang Anda gunakan untuk mengambil data dari penyedia konten.</li>
135        <li>API yang Anda gunakan untuk menyisipkan, memperbarui, atau menghapus data dalam penyedia konten.</li>
136        <li>Fitur API lainnya yang memudahkan kita menggunakan penyedia.</li>
137    </ul>
138
139    <!-- Basics -->
140<h2 id="Basics">Ikhtisar</h2>
141<p>
142    Penyedia konten menyajikan data ke aplikasi eksternal sebagai satu atau beberapa tabel yang
143    serupa dengan tabel-tabel yang ditemukan dalam database relasional. Sebuah baris mewakili instance beberapa tipe
144    data yang dikumpulkan penyedia, dan tiap kolom dalam baris mewakili sepotong
145    data yang dikumpulkan untuk sebuah instance.
146</p>
147<p>
148    Misalnya, salah satu penyedia bawaan di platform Android adalah kamus pengguna, yang
149    menyimpan ejaan kata-kata tidak-standar yang ingin disimpan pengguna. Tabel 1 mengilustrasikan
150    wujud data yang mungkin ada dalam tabel penyedia ini:
151</p>
152<p class="table-caption">
153    <strong>Tabel 1:</strong> Contoh tabel kamus pengguna.
154</p>
155<table id="table1" style="width: 50%;">
156    <tr>
157        <th style="width:20%" align="center" scope="col">word</th>
158        <th style="width:20%" align="center" scope="col">app id</th>
159        <th style="width:20%" align="center" scope="col">frequency</th>
160        <th style="width:20%" align="center" scope="col">locale</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    Dalam tabel 1, tiap baris mewakili instance sebuah kata yang mungkin tidak
201    ditemukan dalam kamus standar. Tiap kolom mewakili beberapa data untuk kata itu, misalnya
202    bahasa lokal tempat kata itu ditemukan kali pertama. Header kolom adalah nama kolom yang disimpan dalam
203    penyedia. Untuk mengacu ke bahasa lokal suatu baris, Anda mengacu ke kolom <code>locale</code>-nya. Untuk
204    penyedia ini, kolom <code>_ID</code> berfungsi sebagai "kunci utama" kolom yang
205    dipelihara oleh penyedia secara otomatis.
206</p>
207<p class="note">
208    <strong>Catatan:</strong> Penyedia tidak diharuskan memiliki kunci utama, dan tidak diharuskan
209    menggunakan <code>_ID</code> sebagai nama kolom kunci utama jika kunci itu ada. Akan tetapi,
210    jika Anda ingin mengikat data dari penyedia ke {@link android.widget.ListView}, salah satu
211    nama kolom harus <code>_ID</code>. Ketentuan ini dijelaskan secara lebih detail di bagian
212    <a href="#DisplayResults">Menampilkan hasil query</a>.
213</p>
214<h3 id="ClientProvider">Mengakses penyedia</h3>
215<p>
216    Aplikasi mengakses data dari penyedia konten dengan
217    sebuah objek klien {@link android.content.ContentResolver}. Objek ini memiliki metode yang memanggil
218    metode dengan nama identik dalam objek penyedia, instance salah satu
219    subkelas konkret dari {@link android.content.ContentProvider}. Metode-metode
220    {@link android.content.ContentResolver} menyediakan fungsi-fungsi dasar
221    "CRUD" (create, retrieve, update, dan delete) pada penyimpanan yang persisten.
222</p>
223<p>
224    Objek {@link android.content.ContentResolver} dalam
225    proses aplikasi klien dan objek {@link android.content.ContentProvider} dalam aplikasi yang memiliki
226    penyedia itu secara otomatis akan menangani komunikasi antar-proses.
227    {@link android.content.ContentProvider} juga berfungsi sebagai lapisan abstraksi antara
228    repository datanya dan penampilan eksternal data sebagai tabel.
229</p>
230<p class="note">
231    <strong>Catatan:</strong> Untuk mengakses penyedia, aplikasi Anda biasanya harus meminta
232    izin tertentu dalam file manifesnya. Hal ini dijelaskan lebih detail di bagian
233    <a href="#Permissions">Izin Penyedia Konten</a>
234</p>
235<p>
236    Misalnya, untuk mendapatkan daftar kata dan lokalnya dari Penyedia Kamus Pengguna,
237    Anda memanggil {@link android.content.ContentResolver#query ContentResolver.query()}.
238    Metode {@link android.content.ContentResolver#query query()} memanggil
239    metode {@link android.content.ContentProvider#query ContentProvider.query()} yang didefinisikan oleh
240    Penyedia Kamus Pengguna. Baris-baris kode berikut menunjukkan sebuah
241    panggilan {@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    Tabel 2 menampilkan cara argumen untuk
254    {@link android.content.ContentResolver#query
255    query(Uri,projection,selection,selectionArgs,sortOrder)} cocok dengan sebuah pernyataan SELECT di SQL:
256</p>
257<p class="table-caption">
258    <strong>Tabel 2:</strong> Query() dibandingkan dengan query SQL.
259</p>
260<table id="table2" style="width: 75%;">
261    <tr>
262        <th style="width:25%" align="center" scope="col">Argumen query()</th>
263        <th style="width:25%" align="center" scope="col">Kata kunci/parameter SELECT</th>
264        <th style="width:50%" align="center" scope="col">Catatan</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> memetakan ke tabel dalam penyedia yang bernama <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> adalah satu larik kolom yang harus disertakan untuk tiap baris
276            yang diambil.
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> menetapkan kriteria untuk memilih baris.</td>
283    </tr>
284    <tr>
285        <td align="center"><code>selectionArgs</code></td>
286        <td align="center">
287            (Tidak ada padanan persis. Argumen pemilihan mengganti <code>?</code> placeholder dalam
288            klausa pemilihan.)
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> menetapkan urutan munculnya baris dalam
296            {@link android.database.Cursor} yang dihasilkan.
297        </td>
298    </tr>
299</table>
300<h3 id="ContentURIs">URI Konten</h3>
301<p>
302    <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten
303    menyertakan nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah
304    nama yang menunjuk ke tabel (<strong>path</strong>). Bila Anda memanggil
305    metode klien untuk mengakses tabel dalam penyedia, URI konten untuk tabel itu adalah salah satu
306    argumennya.
307</p>
308<p>
309    Dalam baris kode sebelumnya, konstanta
310    {@link android.provider.UserDictionary.Words#CONTENT_URI} mengandung URI konten dari
311    tabel "words" kamus pengguna. Objek {@link android.content.ContentResolver}
312    akan mengurai otoritas URI, dan menggunakannya untuk "mengetahui" penyedia dengan
313    membandingkan otoritas tersebut dengan sebuah tabel sistem berisi penyedia yang dikenal.
314{@link android.content.ContentResolver}    kemudian bisa mengirim argumen query ke penyedia
315    yang benar.
316</p>
317<p>
318    {@link android.content.ContentProvider} menggunakan bagian path dari URI konten untuk memilih
319    tabel yang akan diakses. Penyedia biasanya memiliki <strong>path</strong> untuk tiap tabel yang dieksposnya.
320</p>
321<p>
322    Dalam baris kode sebelumnya, URI lengkap untuk tabel "words" adalah:
323</p>
324<pre>
325content://user_dictionary/words
326</pre>
327<p>
328    dalam hal ini string <code>user_dictionary</code> adalah otoritas penyedia, dan string
329    <code>words</code> adalah path tabel. String
330    <code>content://</code> (<strong>skema</strong>) selalu ada,
331    dan mengidentifikasinya sebagai URI konten.
332</p>
333<p>
334    Banyak penyedia yang memperbolehkan Anda mengakses satu baris dalam tabel dengan menambahkan sebuah ID nilai
335    ke akhir URI. Misalnya, untuk mengambil sebuah baris yang <code>_ID</code>-nya adalah
336    <code>4</code> dari kamus pengguna, Anda bisa menggunakan URI konten ini:
337</p>
338<pre>
339Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
340</pre>
341<p>
342    Anda akan sering menggunakan nilai-nilai ID bila telah mengambil satu set baris kemudian ingin memperbarui atau menghapus
343    salah satunya.
344</p>
345<p class="note">
346    <strong>Catatan:</strong> Kelas-kelas {@link android.net.Uri} dan {@link android.net.Uri.Builder}
347    berisi metode praktis untuk membangun objek dari string URI yang tersusun dengan baik.
348{@link android.content.ContentUris}    berisi metode praktis untuk menambahkan nilai ID ke
349    URI. Cuplikan kode sebelumnya menggunakan {@link android.content.ContentUris#withAppendedId
350    withAppendedId()} untuk menambahkan id ke URI konten User Dictionary.
351</p>
352
353
354    <!-- Retrieving Data from the Provider -->
355<h2 id="SimpleQuery">Mengambil Data dari Penyedia</h2>
356<p>
357    Bagian ini menerangkan cara mengambil data dari penyedia, dengan menggunakan Penyedia Kamus Pengguna
358    sebagai contoh.
359</p>
360<p class="note">
361    Demi kejelasan, cuplikan kode di bagian ini memanggil
362    {@link android.content.ContentResolver#query ContentResolver.query()} pada "UI thread"". Akan tetapi, dalam
363    kode sesungguhnya, Anda harus melakukan query secara asinkron pada sebuah thread terpisah. Satu cara melakukannya
364    adalah menggunakan kelas {@link android.content.CursorLoader}, yang dijelaskan
365    lebih detail dalam panduan <a href="{@docRoot}guide/components/loaders.html">
366    Loader</a>. Juga, baris-baris kode tersebut hanyalah cuplikan; tidak menunjukkan sebuah aplikasi
367     lengkap.
368</p>
369<p>
370    Untuk mengambil data dari penyedia, ikutilah langkah-langkah dasar ini:
371</p>
372<ol>
373   <li>
374        Minta izin akses baca untuk penyedia itu.
375   </li>
376   <li>
377        Definisikan kode yang mengirim query ke penyedia.
378   </li>
379</ol>
380<h3 id="RequestPermissions">Meminta izin akses baca</h3>
381<p>
382    Untuk mengambil data dari penyedia, aplikasi Anda memerlukan "izin akses baca" untuk
383    penyedia itu. Anda tidak bisa meminta izin ini saat runtime; sebagai gantinya, Anda harus menetapkan bahwa
384    Anda memerlukan izin ini dalam manifes, dengan menggunakan elemen
385<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
386    dan nama persis izin yang didefinisikan oleh
387    penyedia itu. Bila menetapkan elemen ini dalam manifes, Anda secara efektif "meminta"
388    izin ini untuk aplikasi Anda. Bila pengguna menginstal aplikasi Anda, mereka secara implisit akan memberikan
389    permintaan ini.
390</p>
391<p>
392    Untuk menemukan nama persis dari izin akses baca untuk penyedia yang sedang Anda gunakan, serta
393    nama-nama izin akses lain yang digunakan oleh penyedia, lihatlah dalam
394    dokumentasi penyedia.
395</p>
396<p>
397    Peran izin dalam yang mengakses penyedia dijelaskan lebih detail di bagian
398    <a href="#Permissions">Izin Penyedia Konten</a>.
399</p>
400<p>
401    Penyedia Kamus Pengguna mendefinisikan izin
402    <code>android.permission.READ_USER_DICTIONARY</code> dalam file manifesnya, sehingga
403    aplikasi yang ingin membaca dari penyedia itu harus meminta izin ini.
404</p>
405<!-- Constructing the query -->
406<h3 id="Query">Membuat query</h3>
407<p>
408    Langkah berikutnya dalam mengambil data penyedia adalah membuat query. Cuplikan kode pertama ini
409    mendefinisikan beberapa variabel untuk mengakses Penyedia Kamus Pengguna:
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    Cuplikan berikutnya menampilkan cara menggunakan
430    {@link android.content.ContentResolver#query ContentResolver.query()}, dengan menggunakan Penyedia Kamus Pengguna
431    sebagai contoh. Query klien penyedia serupa dengan query SQL, dan berisi satu
432    set kolom yang akan dihasilkan, satu set kriteria pemilihan, dan urutan sortir.
433</p>
434<p>
435    Set kolom yang harus dikembalikan query disebut dengan <strong>proyeksi</strong>
436    (variabel <code>mProjection</code>).
437</p>
438<p>
439    Ekspresi yang menetapkan baris yang harus diambil dipecah menjadi klausa pemilihan dan
440    argumen pemilihan. Klausa pemilihan adalah kombinasi ekspresi logis dan boolean,
441    nama kolom, dan nilai (variabel <code>mSelectionClause</code>). Jika Anda menetapkan
442    parameter <code>?</code> yang bisa diganti, sebagai ganti nilai, metode query akan mengambil nilai
443    dari larik argumen pemilihan (variabel <code>mSelectionArgs</code>).
444</p>
445<p>
446    Dalam cuplikan berikutnya, jika pengguna tidak memasukkan sebuah kata, klausa pemilihan akan diatur ke
447    <code>null</code>, dan query menghasilkan semua kata dalam penyedia. Jika pengguna memasukkan
448    sebuah kata, klausa pemilihan akan diatur ke <code>UserDictionary.Words.WORD + " = ?"</code> dan
449    elemen pertama larik argumen pemilihan diatur ke kata yang dimasukkan pengguna.
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    Query ini analog dengan pernyataan 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    Dalam pernyataan SQL ini, nama kolom yang sesungguhnya digunakan sebagai ganti konstanta kelas kontrak.
514</p>
515<h4 id="Injection">Melindungi dari input merusak</h4>
516<p>
517    Jika data dikelola oleh penyedia konten berada dalam database SQL, memasukkan data tak dipercaya eksternal
518    ke dalam pernyataan SQL mentah bisa menyebabkan injeksi SQL.
519</p>
520<p>
521    Perhatikan klausa pemilihan ini:
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    Jika melakukannya, Anda akan membuat pengguna menyambungkan SQL merusak ke pernyataan SQL Anda.
529    Misalnya, pengguna bisa memasukkan "nothing; DROP TABLE *;"  untuk <code>mUserInput</code>, yang
530    akan menghasilkan klausa pemilihan <code>var = nothing; DROP TABLE *;</code>. Karena
531    klausa pemilihan diperlakukan sebagai pernyataan SQL, hal ini bisa menyebabkan penyedia itu menghapus semua
532    tabel dalam database SQLite yang mendasarinya (kecuali penyedia disiapkan untuk menangkap upaya
533    <a href="http://en.wikipedia.org/wiki/SQL_injection">injeksi SQL</a>).
534</p>
535<p>
536    Untuk menghindari masalah ini, gunakan klausa pemilihan yang menggunakan <code>?</code> sebagai
537    parameter yang bisa diganti dan larik argumen pemilihan yang terpisah. Bila Anda melakukannya, input pengguna
538    akan dibatasi secara langsung pada query agar tidak ditafsirkan sebagai bagian dari pernyataan SQL.
539    Karena tidak diperlakukan sebagai SQL, input pengguna tidak bisa menyuntikkan SQL merusak. Sebagai ganti menggunakan
540    penyambungan untuk menyertakan input pengguna, gunakan klausa pemilihan ini:
541</p>
542<pre>
543// Constructs a selection clause with a replaceable parameter
544String mSelectionClause =  "var = ?";
545</pre>
546<p>
547    Buat larik argumen pemilihan seperti ini:
548</p>
549<pre>
550// Defines an array to contain the selection arguments
551String[] selectionArgs = {""};
552</pre>
553<p>
554    Masukkan nilai dalam larik argumen pemilihan seperti ini:
555</p>
556<pre>
557// Sets the selection argument to the user's input
558selectionArgs[0] = mUserInput;
559</pre>
560<p>
561    Sebuah klausa pemilihan yang menggunakan <code>?</code> sebagai parameter yang bisa diganti dan sebuah larik
562    argumen pemilihan adalah cara yang lebih disukai untuk menyebutkan pemilihan, sekalipun penyedia tidak
563    dibuat berdasarkan database SQL.
564</p>
565<!-- Displaying the results -->
566<h3 id="DisplayResults">Menampilkan hasil query</h3>
567<p>
568    Metode klien {@link android.content.ContentResolver#query ContentResolver.query()} selalu
569    menghasilkan {@link android.database.Cursor} berisi kolom-kolom yang ditetapkan oleh
570    proyeksi query untuk baris yang cocok dengan kriteria pemilihan query. Objek
571    {@link android.database.Cursor} menyediakan akses baca acak ke baris dan kolom yang
572    dimuatnya. Dengan metode {@link android.database.Cursor}, Anda bisa mengulang baris-baris dalam
573    hasil, menentukan tipe data tiap kolom, mengambil data dari kolom, dan memeriksa
574    properti lain dari hasil. Beberapa implementasi {@link android.database.Cursor}
575    akan memperbarui objek secara otomatis bila data penyedia berubah, atau memicu metode dalam objek pengamat
576    bila {@link android.database.Cursor} berubah, atau keduanya.
577</p>
578<p class="note">
579    <strong>Catatan:</strong> Penyedia bisa membatasi akses ke kolom berdasarkan sifat
580    objek yang membuat query. Misalnya, Penyedia Kontak membatasi akses untuk beberapa kolom pada
581    adaptor sinkronisasi, sehingga tidak akan mengembalikannya ke aktivitas atau layanan.
582</p>
583<p>
584    Jika tidak ada baris yang cocok dengan kriteria pemilihan, penyedia
585    akan mengembalikan objek {@link android.database.Cursor} dengan
586    {@link android.database.Cursor#getCount Cursor.getCount()} adalah 0 (kursor kosong).
587</p>
588<p>
589    Jika terjadi kesalahan internal, hasil query akan bergantung pada penyedia tertentu. Penyedia bisa
590    memilih untuk menghasilkan <code>null</code>, atau melontarkan {@link java.lang.Exception}.
591</p>
592<p>
593    Karena {@link android.database.Cursor} adalah "daftar" baris, cara yang cocok untuk menampilkan
594    konten {@link android.database.Cursor} adalah mengaitkannya dengan {@link android.widget.ListView}
595    melalui {@link android.widget.SimpleCursorAdapter}.
596</p>
597<p>
598    Cuplikan berikut melanjutkan kode dari cuplikan sebelumnya. Cuplikan ini membuat
599    objek {@link android.widget.SimpleCursorAdapter} berisi {@link android.database.Cursor}
600    yang diambil oleh query, dan mengatur objek ini menjadi adaptor bagi
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>Catatan:</strong> Untuk mendukung {@link android.widget.ListView} dengan
628    {@link android.database.Cursor}, kursor harus berisi kolom bernama <code>_ID</code>.
629    Karena itu, query yang ditampilkan sebelumnya mengambil kolom <code>_ID</code> untuk
630    tabel "words", walaupun {@link android.widget.ListView} tidak menampilkannya.
631    Pembatasan ini juga menjelaskan mengapa sebagian besar penyedia memiliki kolom <code>_ID</code> untuk masing-masing
632    tabelnya.
633</p>
634
635        <!-- Getting data from query results -->
636<h3 id="GettingResults">Mendapatkan data dari hasil query</h3>
637<p>
638    Daripada sekadar menampilkan hasil query, Anda bisa menggunakannya untuk tugas-tugas lain. Misalnya,
639    Anda bisa mengambil ejaan dari kamus pengguna kemudian mencarinya dalam
640    penyedia lain. Caranya, ulangi baris-baris dalam {@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    Implementasi {@link android.database.Cursor} berisi beberapa metode "get" untuk
676    mengambil berbagai tipe data dari objek. Misalnya, cuplikan sebelumnya
677    menggunakan {@link android.database.Cursor#getString getString()}. Implementasi juga memiliki
678    metode {@link android.database.Cursor#getType getType()} yang menghasilkan nilai yang menunjukkan
679    tipe data kolom.
680</p>
681
682
683    <!-- Requesting permissions -->
684<h2 id="Permissions">Izin Penyedia Konten</h2>
685<p>
686    Aplikasi penyedia bisa menetapkan izin yang harus dimiliki aplikasi lain untuk
687    mengakses data penyedia. Izin ini akan memastikan bahwa pengguna mengetahui data
688    yang coba diakses oleh aplikasi. Berdasarkan ketentuan penyedia, aplikasi lain
689    meminta izin yang diperlukannya untuk mengakses penyedia. Pengguna akhir akan melihat
690    izin yang diminta saat menginstal aplikasi.
691</p>
692<p>
693    Jika aplikasi penyedia tidak menetapkan izin apa pun, maka aplikasi lain tidak memiliki
694    akses ke data penyedia. Akan tetapi, komponen-komponen dalam aplikasi penyedia selalu memiliki
695    akses penuh untuk baca dan tulis, izin apa pun yang ditetapkan.
696</p>
697<p>
698    Seperti disebutkan sebelumnya, Penyedia Kamus Pengguna mensyaratkan izin
699    <code>android.permission.READ_USER_DICTIONARY</code> untuk mengambil data darinya.
700    Penyedia memiliki izin <code>android.permission.WRITE_USER_DICTIONARY</code>
701    yang terpisah untuk menyisipkan, memperbarui, atau menghapus data.
702</p>
703<p>
704    Untuk mendapatkan izin yang diperlukan untuk mengakses penyedia, aplikasi memintanya dengan elemen
705<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
706    dalam file manifesnya. Bila Android Package Manager memasang aplikasi, pengguna
707    harus menyetujui semua izin yang diminta aplikasi. Jika pengguna menyetujui semuanya,
708    Package Manager akan melanjutkan instalasi; jika pengguna tidak menyetujui, Package Manager
709    akan membatalkan instalasi.
710</p>
711<p>
712    Elemen
713<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
714    berikut meminta akses baca ke Penyedia Kamus Pengguna:
715</p>
716<pre>
717    &lt;uses-permission android:name="android.permission.READ_USER_DICTIONARY"&gt;
718</pre>
719<p>
720    Dampak izin pada akses penyedia dijelaskan secara lebih detail dalam panduan
721    <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>.
722</p>
723
724
725<!-- Inserting, Updating, and Deleting Data -->
726<h2 id="Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</h2>
727<p>
728    Lewat cara yang sama dengan cara mengambil data dari penyedia, Anda juga menggunakan interaksi antara
729    klien penyedia dan {@link android.content.ContentProvider} penyedia untuk memodifikasi data.
730    Anda memanggil metode {@link android.content.ContentResolver} dengan argumen yang diteruskan ke
731    metode {@link android.content.ContentProvider} yang sesuai. Penyedia dan klien penyedia
732    menangani secara otomatis keamanan dan komunikasi antar-proses.
733</p>
734<h3 id="Inserting">Menyisipkan data</h3>
735<p>
736    Untuk menyisipkan data ke penyedia, Anda memanggil metode
737    {@link android.content.ContentResolver#insert ContentResolver.insert()}.
738 Metode ini menyisipkan sebuah baris baru ke penyedia itu dan menghasilkan URI konten untuk baris itu.
739    Cuplikan ini menampilkan cara menyisipkan sebuah kata baru ke Penyedia Kamus Pengguna:
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    Data untuk baris baru masuk ke dalam satu objek {@link android.content.ContentValues}, yang
766    serupa bentuknya dengan kursor satu-baris. Kolom dalam objek ini tidak perlu memiliki
767    tipe data yang sama, dan jika Anda tidak ingin menetapkan nilai sama sekali, Anda bisa mengatur kolom
768    ke <code>null</code> dengan menggunakan {@link android.content.ContentValues#putNull ContentValues.putNull()}.
769</p>
770<p>
771    Cuplikan ini tidak menambahkan kolom <code>_ID</code>, karena kolom ini dipelihara
772    secara otomatis. Penyedia menetapkan sebuah nilai unik <code>_ID</code> ke setiap baris yang
773    ditambahkan. Penyedia biasanya menggunakan nilai ini sebagai kunci utama tabel.
774</p>
775<p>
776    URI konten yang dihasilkan dalam <code>newUri</code> akan mengidentifikasi baris yang baru ditambahkan, dengan
777    format berikut:
778</p>
779<pre>
780content://user_dictionary/words/&lt;id_value&gt;
781</pre>
782<p>
783    <code>&lt;id_value&gt;</code> adalah konten <code>_ID</code> untuk baris baru.
784    Kebanyakan penyedia bisa mendeteksi bentuk URI konten ini secara otomatis kemudian melakukan
785    operasi yang diminta pada baris tersebut.
786</p>
787<p>
788    Untuk mendapatkan nilai <code>_ID</code> dari {@link android.net.Uri} yang dihasilkan, panggil
789    {@link android.content.ContentUris#parseId ContentUris.parseId()}.
790</p>
791<h3 id="Updating">Memperbarui data</h3>
792<p>
793    Untuk memperbarui sebuah baris, gunakan objek {@link android.content.ContentValues} dengan
794    nilai-nilai yang diperbarui, persis seperti yang Anda lakukan pada penyisipan, dan kriteria pemilihan persis seperti yang Anda lakukan pada query.
795    Metode klien yang Anda gunakan adalah
796    {@link android.content.ContentResolver#update ContentResolver.update()}. Anda hanya perlu menambahkan
797    nilai-nilai ke objek {@link android.content.ContentValues} untuk kolom yang sedang Anda perbarui. Jika Anda
798    ingin membersihkan konten kolom, aturlah nilai ke <code>null</code>.
799</p>
800<p>
801    Cuplikan berikut mengubah semua baris yang kolom lokalnya memiliki bahasa "en" ke
802    lokal <code>null</code>. Nilai hasil adalah jumlah baris yang diperbarui:
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    Anda juga harus membersihkan input pengguna bila memanggil
831    {@link android.content.ContentResolver#update ContentResolver.update()}. Untuk mengetahui selengkapnya tentang
832    hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>.
833</p>
834<h3 id="Deleting">Menghapus data</h3>
835<p>
836    Menghapus baris serupa dengan mengambil baris data: Anda menetapkan kriteria pemilihan untuk baris
837    yang ingin Anda hapus dan metode klien akan menghasilkan jumlah baris yang dihapus.
838    Cuplikan berikut menghapus baris yang appid-nya sama dengan "user". Metode menghasilkan
839    jumlah baris yang dihapus.
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    Anda juga harus membersihkan input pengguna bila memanggil
861    {@link android.content.ContentResolver#delete ContentResolver.delete()}. Untuk mengetahui selengkapnya tentang
862    hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>.
863</p>
864<!-- Provider Data Types -->
865<h2 id="DataTypes">Tipe Data Penyedia</h2>
866<p>
867    Penyedia konten bisa menawarkan berbagai tipe data. Penyedia Kamus Pengguna hanya menawarkan
868    teks, namun penyedia juga bisa menawarkan format berikut:
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    Tipe data lain yang sering digunakan penyedia adalah Binary Large OBject (BLOB) yang diimplementasikan sebagai
886    larik byte 64 KB. Anda bisa melihat tipe data yang tersedia dengan memperhatikan metode "get"
887    kelas {@link android.database.Cursor}.
888</p>
889<p>
890    Tipe data tiap kolom dalam penyedia biasanya tercantum dalam dokumentasinya.
891    Tipe data untuk Penyedia Kamus Pengguna tercantum dalam dokumentasi acuan
892    untuk kelas kontraknya {@link android.provider.UserDictionary.Words} (kelas kontrak
893    dijelaskan di bagian <a href="#ContractClasses">Kelas-kelas Kontrak</a>).
894    Anda juga bisa menentukan tipe data dengan memanggil {@link android.database.Cursor#getType
895    Cursor.getType()}.
896</p>
897<p>
898    Penyedia juga memelihara informasi tipe data MIME untuk tiap URI konten yang didefinisikannya. Anda bisa
899    menggunakan informasi tipe MIME untuk mengetahui apakah aplikasi Anda bisa menangani data yang
900    disediakan penyedia, atau memilih tipe penanganan berdasarkan tipe MIME. Anda biasanya memerlukan
901    tipe MIME saat menggunakan penyedia yang berisi
902    struktur atau file data yang kompleks. Misalnya, tabel {@link android.provider.ContactsContract.Data}
903    dalam Penyedia Kontak menggunakan tipe MIME untuk memberi label tipe data kontak yang disimpan di tiap
904    baris. Untuk mendapatkan tipe MIME yang sesuai dengan URI konten, panggil
905    {@link android.content.ContentResolver#getType ContentResolver.getType()}.
906</p>
907<p>
908    Bagian <a href="#MIMETypeReference">Acuan Tipe MIME</a> menerangkan
909    sintaks tipe MIME baik yang standar maupun custom.
910</p>
911
912
913<!-- Alternative Forms of Provider Access -->
914<h2 id="AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</h2>
915<p>
916    Tiga bentuk alternatif akses penyedia adalah penting dalam pengembangan aplikasi:
917</p>
918<ul>
919    <li>
920        <a href="#Batch">Akses batch</a>: Anda bisa membuat sebuah batch panggilan akses dengan metode-metode dalam
921        kelas {@link android.content.ContentProviderOperation}, kemudian menerapkannya dengan
922        {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}.
923    </li>
924    <li>
925        Query asinkron: Anda harus melakukan query dalam thread terpisah. Satu cara melakukannya adalah
926        menggunakan objek {@link android.content.CursorLoader}. Contoh-contoh dalam panduan
927        <a href="{@docRoot}guide/components/loaders.html">Loader</a> memperagakan
928        cara melakukannya.
929    </li>
930    <li>
931        <a href="#Intents">Akses data melalui intent</a>: Walaupun tidak bisa mengirim intent
932        ke penyedia secara langsung, Anda bisa mengirim intent ke aplikasi penyedia, yang
933        biasanya paling lengkap dibekali untuk memodifikasi data penyedia.
934    </li>
935</ul>
936<p>
937    Akses batch dan modifikasi melalui intent dijelaskan dalam bagian-bagian berikut.
938</p>
939<h3 id="Batch">Akses batch</h3>
940<p>
941    Akses batch ke penyedia berguna untuk menyisipkan baris dalam jumlah besar, atau menyisipkan
942    baris ke dalam beberapa tabel dalam panggilan metode yang sama, atau biasanya melakukan satu set
943    operasi lintas batas proses sebagai transaksi (operasi atomik).
944</p>
945<p>
946    Untuk mengakses penyedia dalam "mode batch",
947    buat satu larik objek {@link android.content.ContentProviderOperation}, kemudian
948    kirim larik itu ke penyedia konten dengan
949    {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. Anda meneruskan
950    <em>otoritas</em> penyedia konten ke metode ini, daripada URI konten tertentu.
951    Ini memungkinkan tiap objek {@link android.content.ContentProviderOperation} dalam larik untuk bekerja
952    terhadap tabel yang berbeda. Panggilan ke {@link android.content.ContentResolver#applyBatch
953    ContentResolver.applyBatch()} menghasilkan satu larik hasil.
954</p>
955<p>
956    Keterangan kelas kontrak {@link android.provider.ContactsContract.RawContacts}
957    menyertakan cuplikan kode yang memperagakan penyisipan batch. Contoh aplikasi
958    <a href="{@docRoot}resources/samples/ContactManager/index.html">Contacts Manager</a>
959    berisi contoh akses batch dalam file sumber <code>ContactAdder.java</code>-nya
960.
961</p>
962<div class="sidebox-wrapper">
963<div class="sidebox">
964<h2>Menampilkan data dengan aplikasi pembantu</h2>
965<p>
966    Jika aplikasi Anda <em>memang</em> memiliki izin akses, Anda masih mungkin perlu menggunakan
967    intent untuk menampilkan data dalam aplikasi lain. Misalnya, aplikasi Kalender menerima
968    intent {@link android.content.Intent#ACTION_VIEW}, yang menampilkan tanggal atau kejadian tertentu.
969    Hal ini memungkinkan Anda menampilkan informasi kalender tanpa harus membuat UI sendiri.
970    Untuk mengetahui selengkapnya tentang fitur ini, lihat panduan
971    <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Penyedia Kalender</a>.
972</p>
973<p>
974    Aplikasi yang Anda kirimi intent tidak harus aplikasi
975    yang terkait dengan penyedia. Misalnya, Anda bisa mengambil satu kontak dari
976    Penyedia Kontak, kemudian mengirim intent {@link android.content.Intent#ACTION_VIEW}
977    berisi URI konten untuk gambar kontak itu ke penampil gambar.
978</p>
979</div>
980</div>
981<h3 id="Intents">Akses data melalui intent</h3>
982<p>
983    Intent bisa menyediakan akses tidak langsung ke penyedia konten. Anda memperbolehkan pengguna mengakses
984    data dalam penyedia sekalipun aplikasi Anda tidak memiliki izin akses, baik dengan
985    mendapatkan intent yang dihasilkan aplikasi yang memiliki izin, atau dengan mengaktifkan
986    aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaan di dalamnya.
987</p>
988<h4>Mendapatkan akses dengan izin sementara</h4>
989<p>
990    Anda bisa mengakses data dalam penyedia konten, sekalipun tidak memiliki
991    izin akses yang sesuai, dengan mengirimkan intent ke aplikasi yang memang memiliki izin dan
992    menerima hasil berupa intent berisi izin "URI".
993    Inilah izin untuk URI konten tertentu yang berlaku hingga aktivitas yang menerima
994    izin selesai. Aplikasi yang memiliki izin tetap akan memberikan
995    izin sementara dengan mengatur flag dalam intent yang dihasilkan:
996</p>
997<ul>
998    <li>
999        <strong>Izin baca:</strong>
1000        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}
1001    </li>
1002    <li>
1003        <strong>Izin tulis:</strong>
1004        {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}
1005    </li>
1006</ul>
1007<p class="note">
1008    <strong>Catatan:</strong> Flag ini tidak memberikan akses baca atau tulis umum ke penyedia
1009    yang otoritasnya dimuat dalam URI konten. Aksesnya hanya untuk URI itu sendiri.
1010</p>
1011<p>
1012    Penyedia mendefinisikan izin URI untuk URI konten dalam manifesnya, dengan menggunakan atribut
1013<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code>
1014    dari elemen
1015<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
1016,   serta elemen anak
1017<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
1018    dari elemen
1019<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>.
1020 Mekanisme izin URI dijelaskan secara lebih detail dalam panduan
1021    <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>,
1022    di bagian "Izin URI".
1023</p>
1024<p>
1025    Misalnya, Anda bisa mengambil data untuk satu kontak di Penyedia Kontak, sekalipun tidak
1026    memiliki izin {@link android.Manifest.permission#READ_CONTACTS}. Anda mungkin ingin melakukan
1027    ini dalam aplikasi yang mengirim kartu ucapan elektronik ke seorang kenalan pada hari ulang tahunnya. Sebagai ganti
1028    meminta {@link android.Manifest.permission#READ_CONTACTS}, yang memberi Anda akses ke semua
1029    kontak pengguna dan semua informasinya, Anda lebih baik membiarkan pengguna mengontrol
1030    kontak-kontak yang akan digunakan oleh aplikasi Anda. Caranya, gunakan proses berikut:
1031</p>
1032<ol>
1033    <li>
1034        Aplikasi Anda akan mengirim intent berisi tindakan
1035        {@link android.content.Intent#ACTION_PICK} dan tipe MIME "contacts"
1036        {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, dengan menggunakan
1037        metode {@link android.app.Activity#startActivityForResult
1038        startActivityForResult()}.
1039    </li>
1040    <li>
1041        Karena intent ini cocok dengan filter intent untuk
1042        aktivitas "pemilihan" aplikasi People, aktivitas akan muncul ke latar depan.
1043    </li>
1044    <li>
1045        Dalam aktivitas pemilihan, pengguna memilih sebuah
1046        kontak untuk diperbarui. Bila ini terjadi, aktivitas pemilihan akan memanggil
1047        {@link android.app.Activity#setResult setResult(resultcode, intent)}
1048        untuk membuat intent yang akan diberikan kembali ke aplikasi Anda. Intent itu berisi URI konten
1049        kontak yang dipilih pengguna, dan flag "extras"
1050        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. Semua flag ini memberikan
1051        izin URI ke aplikasi Anda untuk membaca data kontak yang ditunjuk oleh
1052        URI konten. Aktivitas pemilihan kemudian memanggil {@link android.app.Activity#finish()} untuk
1053        mengembalikan kontrol ke aplikasi Anda.
1054    </li>
1055    <li>
1056        Aktivitas Anda akan kembali ke latar depan, dan sistem memanggil metode
1057        {@link android.app.Activity#onActivityResult onActivityResult()}
1058        aktivitas Anda. Metode ini menerima intent yang dihasilkan oleh aktivitas pemilihan dalam
1059        aplikasi People.
1060    </li>
1061    <li>
1062        Dengan URI konten dari intent yang dihasilkan, Anda bisa membaca data kontak
1063        dari Penyedia Kontak, sekalipun Anda tidak meminta izin akses baca tetap
1064        ke penyedia dalam manifes Anda. Anda kemudian bisa mendapatkan informasi hari ulang tahun si kontak
1065        atau alamat emailnya, kemudian mengirim kartu ucapan elektronik.
1066    </li>
1067</ol>
1068<h4>Menggunakan aplikasi lain</h4>
1069<p>
1070    Satu cara mudah agar pengguna bisa memodifikasi data yang izin aksesnya tidak Anda miliki adalah
1071    mengaktifkan aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaannya di sana.
1072</p>
1073<p>
1074    Misalnya, aplikasi Kalender menerima
1075    intent {@link android.content.Intent#ACTION_INSERT}, yang memungkinkan Anda mengaktifkan
1076    UI penyisipan aplikasi itu. Anda bisa meneruskan data "extras" dalam intent ini, yang
1077    digunakan aplikasi untuk mengisi dahulu UI-nya. Karena kejadian berulang memiliki sintaks yang rumit,
1078    cara yang lebih disukai untuk menyisipkan kejadian ke dalam Penyedia Kalender adalah mengaktifkan aplikasi Kalender dengan
1079    {@link android.content.Intent#ACTION_INSERT}, kemudian membiarkan pengguna menyisipkan kejadian di sana.
1080</p>
1081<!-- Contract Classes -->
1082<h2 id="ContractClasses">Kelas-kelas Kontrak</h2>
1083<p>
1084    Kelas kontrak mendefinisikan konstanta yang membantu aplikasi menggunakan URI konten, nama
1085    kolom, tindakan intent, dan fitur lain pada penyedia konten. Kelas kontrak tidak
1086    disertakan secara otomatis bersama penyedia; pengembang penyedia harus mendefinisikannya kemudian
1087    membuatnya tersedia bagi pengembang lain. Banyak penyedia yang disertakan pada platform Android
1088    memiliki kelas kontrak yang sesuai dalam {@link android.provider} paketnya.
1089</p>
1090<p>
1091    Misalnya, Penyedia Kamus Pengguna memiliki kelas kontrak
1092    {@link android.provider.UserDictionary} yang berisi URI konten dan konstanta nama kolom. URI
1093    konten untuk tabel "words" didefinisikan dalam konstanta
1094    {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}.
1095    Kelas {@link android.provider.UserDictionary.Words} juga berisi konstanta nama kolom,
1096    yang digunakan dalam cuplikan contoh pada panduan ini. Misalnya, sebuah proyeksi query bisa
1097    didefinisikan sebagai:
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    Kelas kontrak lain adalah {@link android.provider.ContactsContract} untuk Penyedia Kontak.
1109    Dokumentasi acuan untuk kelas ini menyertakan contoh cuplikan kode. Salah satu
1110    subkelasnya, {@link android.provider.ContactsContract.Intents.Insert}, adalah
1111    kelas kontrak yang berisi konstanta untuk intent dan data intent.
1112</p>
1113
1114
1115<!-- MIME Type Reference -->
1116<h2 id="MIMETypeReference">Acuan Tipe MIME</h2>
1117<p>
1118    Penyedia konten bisa menghasilkan tipe media MIME standar, atau string tipe MIME custom, atau keduanya.
1119</p>
1120<p>
1121    Tipe MIME memiliki format
1122</p>
1123<pre>
1124<em>type</em>/<em>subtype</em>
1125</pre>
1126<p>
1127    Misalnya, tipe MIME <code>text/html</code> yang dikenal luas memiliki tipe <code>text</code> dan
1128    subtipe <code>html</code>. Jika penyedia menghasilkan tipe ini untuk sebuah URI, artinya
1129    query dengan URI itu akan menghasilkan teks berisi tag HTML.
1130</p>
1131<p>
1132    String tipe MIME custom, yang juga disebut dengan tipe MIME "khusus vendor", memiliki nilai-nilai
1133    <em>tipe</em> dan <em>subtipe</em> yang lebih kompleks. Nilai <em>tipe</em> selalu
1134</p>
1135<pre>
1136vnd.android.cursor.<strong>dir</strong>
1137</pre>
1138<p>
1139    untuk beberapa baris, atau
1140</p>
1141<pre>
1142vnd.android.cursor.<strong>item</strong>
1143</pre>
1144<p>
1145    untuk satu baris.
1146</p>
1147<p>
1148    <em>Subtipe</em> adalah khusus penyedia. Penyedia bawaan Android biasanya memiliki subtipe
1149    sederhana. Misalnya, bila aplikasi Contacts membuat satu baris untuk nomor telepon,
1150    aplikasi akan mengatur tipe MIME berikut di baris itu:
1151</p>
1152<pre>
1153vnd.android.cursor.item/phone_v2
1154</pre>
1155<p>
1156    Perhatikan bahwa nilai subtipe adalah sekadar <code>phone_v2</code>.
1157</p>
1158<p>
1159    Pengembang penyedia lain bisa membuat pola subtipe sendiri berdasarkan
1160    otoritas dan nama-nama tabel penyedia. Misalnya, perhatikan penyedia yang berisi jadwal kereta api.
1161    Otoritas penyedia adalah <code>com.example.trains</code>, dan berisi tabel-tabel
1162    Line1, Line2, dan Line3. Untuk merespons URI konten
1163</p>
1164<p>
1165<pre>
1166content://com.example.trains/Line1
1167</pre>
1168<p>
1169    untuk tabel Line1, penyedia menghasilkan tipe MIME
1170</p>
1171<pre>
1172vnd.android.cursor.<strong>dir</strong>/vnd.example.line1
1173</pre>
1174<p>
1175     Untuk merespons URI konten
1176</p>
1177<pre>
1178content://com.example.trains/Line2/5
1179</pre>
1180<p>
1181    untuk baris 5 di tabel Line2, penyedia menghasilkan tipe MIME
1182</p>
1183<pre>
1184vnd.android.cursor.<strong>item</strong>/vnd.example.line2
1185</pre>
1186<p>
1187    Kebanyakan penyedia konten mendefinisikan konstanta kelas kontrak untuk tipe MIME yang digunakannya. Kelas kontrak
1188    {@link android.provider.ContactsContract.RawContacts} pada Penyedia Kontak
1189    misalnya, mendefinisikan konstanta
1190    {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} untuk tipe MIME
1191    baris kontak mentah tunggal.
1192</p>
1193<p>
1194    URI konten untuk baris-baris tunggal dijelaskan di bagian
1195    <a href="#ContentURIs">URI Konten</a>.
1196</p>
1197