• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Membuat Penyedia Konten
2@jd:body
3<div id="qv-wrapper">
4<div id="qv">
5
6
7<h2>Dalam dokumen ini</h2>
8<ol>
9    <li>
10        <a href="#DataStorage">Mendesain Penyimpanan Data</a>
11    </li>
12    <li>
13        <a href="#ContentURI">Mendesain URI Konten</a>
14    </li>
15    <li>
16        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>
17        <ol>
18            <li>
19                <a href="#RequiredAccess">Metode-Metode yang Diperlukan</a>
20            </li>
21            <li>
22                <a href="#Query">Mengimplementasikan metode query()</a>
23            </li>
24            <li>
25                <a href="#Insert">Mengimplementasikan metode insert()</a>
26            </li>
27            <li>
28                <a href="#Delete">Mengimplementasikan metode delete()</a>
29            </li>
30            <li>
31                <a href="#Update">Mengimplementasikan metode update()</a>
32            </li>
33            <li>
34                <a href="#OnCreate">Mengimplementasikan metode onCreate()</a>
35            </li>
36        </ol>
37    </li>
38    <li>
39        <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>
40        <ol>
41            <li>
42                <a href="#TableMIMETypes">Tipe MIME untuk tabel</a>
43            </li>
44            <li>
45                <a href="#FileMIMETypes">Tipe MIME untuk file</a>
46            </li>
47        </ol>
48    </li>
49    <li>
50        <a href="#ContractClass">Mengimplementasikan Kelas Kontrak</a>
51    </li>
52    <li>
53        <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a>
54    </li>
55    <li>
56        <a href="#ProviderElement">Elemen &lt;provider&gt;</a>
57    </li>
58    <li>
59        <a href="#Intents">Intent dan Akses Data</a>
60    </li>
61</ol>
62<h2>Kelas-kelas utama</h2>
63    <ol>
64        <li>
65            {@link android.content.ContentProvider}
66        </li>
67        <li>
68            {@link android.database.Cursor}
69        </li>
70        <li>
71            {@link android.net.Uri}
72        </li>
73    </ol>
74<h2>Contoh-Contoh Terkait</h2>
75    <ol>
76        <li>
77            <a href="{@docRoot}resources/samples/NotePad/index.html">
78                Aplikasi contoh Note Pad
79            </a>
80        </li>
81    </ol>
82<h2>Lihat juga</h2>
83    <ol>
84        <li>
85            <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
86            Dasar-Dasar Penyedia Konten</a>
87        </li>
88        <li>
89            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
90            Penyedia Kalender</a>
91        </li>
92    </ol>
93</div>
94</div>
95
96
97<p>
98    Penyedia konten mengelola akses ke repository data pusat. Anda mengimplementasikan
99    penyedia sebagai satu atau beberapa kelas dalam aplikasi Android, bersama elemen-elemen dalam
100    file manifes. Salah satu kelas Anda mengimplementasikan subkelas
101    {@link android.content.ContentProvider}, yang merupakan antarmuka antara penyedia Anda dan
102    aplikasi lain. Walaupun penyedia konten dimaksudkan untuk menyediakan data bagi
103    aplikasi lain, Anda tentu saja bisa memiliki aktivitas dalam aplikasi yang memungkinkan pengguna
104    melakukan query dan memodifikasi data yang dikelola oleh penyedia Anda.
105</p>
106<p>
107    Bagian selebihnya dalam topik ini adalah daftar langkah-langkah dasar untuk membangun penyedia konten dan daftar
108    API yang akan digunakan.
109</p>
110
111
112<!-- Before You Start Building -->
113<h2 id="BeforeYouStart">Sebelum Anda Mulai Membangun</h2>
114<p>
115    Sebelum Anda mulai membangun penyedia, lakukanlah hal-hal berikut:
116</p>
117<ol>
118    <li>
119        <strong>Putuskan apakah Anda memerlukan penyedia konten</strong>. Anda perlu membangun sebuah
120        penyedia konten jika ingin menyediakan salah satu atau beberapa dari fitur berikut:
121        <ul>
122            <li>Anda ingin menawarkan data atau file yang kompleks ke aplikasi lain.</li>
123            <li>Anda ingin memungkinkan pengguna menyalin data yang kompleks dari aplikasi Anda ke dalam aplikasi lain.</li>
124            <li>Anda ingin menyediakan saran pencarian custom dengan menggunakan kerangka kerja pencarian.</li>
125        </ul>
126    <p>
127        Anda <em>tidak</em> mengharuskan penyedia untuk menggunakan database SQLite jika hanya digunakan dalam
128        aplikasi sendiri.
129    </p>
130    </li>
131    <li>
132        Jika Anda belum siap melakukannya, bacalah topik
133        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
134        Dasar-Dasar Penyedia Konten</a> untuk mengetahui selengkapnya tentang penyedia.
135    </li>
136</ol>
137<p>
138    Berikutnya, ikuti langkah-langkah ini untuk membangun penyedia:
139</p>
140<ol>
141    <li>
142        Desain penyimpanan mentah untuk data Anda. Penyedia konten menawarkan data dengan dua cara:
143        <dl>
144            <dt>
145                Data file
146            </dt>
147            <dd>
148                Data yang biasanya masuk ke dalam file, misalnya
149                foto, audio, atau video. Simpan file dalam ruang privat
150                aplikasi Anda. Untuk merespons permintaan file dari aplikasi lain,
151                penyedia Anda bisa menawarkan handle ke file tersebut.
152            </dd>
153            <dt>
154                Data "terstruktur"
155            </dt>
156            <dd>
157                Data yang biasanya masuk ke dalam database, larik, atau struktur serupa.
158                Simpan data dalam bentuk yang kompatibel dengan tabel berisi baris dan kolom. Baris
159                mewakili entitas, misalnya satu orang atau satu barang inventori. Kolom mewakili
160                beberapa data untuk entitas itu, misalnya nama orang atau harga barang. Cara umum untuk
161                menyimpan tipe data ini adalah dalam database SQLite, namun Anda bisa menggunakan tipe
162                penyimpanan apa saja yang persisten. Untuk mengetahui selengkapnya tentang tipe penyimpanan yang tersedia di
163                sistem Android, lihat bagian <a href="#DataStorage">
164                Mendesain Penyimpanan Data</a>.
165            </dd>
166        </dl>
167    </li>
168    <li>
169        Definisikan sebuah implementasi konkret kelas {@link android.content.ContentProvider} dan
170        metode yang diperlukannya. Kelas ini adalah antarmuka antara data Anda dan bagian selebihnya pada
171        sistem Android. Untuk informasi selengkapnya tentang kelas ini, lihat bagian
172        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>.
173    </li>
174    <li>
175        Definisikan string otoritas, semua URI isinya, dan nama-nama kolom penyedia. Jika Anda ingin
176        penyedia aplikasi menangani intent, definisikan juga semua tindakan intent, data ekstra,
177        dan flag. Definisikan juga izin yang akan Anda syaratkan terhadap aplikasi yang ingin
178        mengakses data Anda. Anda harus mempertimbangkan pendefinisian semua nilai ini sebagai konstanta di
179        kelas kontrak terpisah; nantinya, Anda bisa mengekspos kelas ini kepada pengembang lain. Untuk
180        informasi selengkapnya tentang URI konten, lihat
181        bagian <a href="#ContentURI">Mendesain URI Konten</a>.
182        Untuk informasi selengkapnya tentang intent, lihat
183        bagian <a href="#Intents">Intent dan Akses Data</a>.
184    </li>
185    <li>
186        Tambahkan bagian opsional lainnya, seperti data contoh atau implementasi
187        {@link android.content.AbstractThreadedSyncAdapter} yang bisa menyinkronkan data antara
188        penyedia dan data berbasis cloud.
189    </li>
190</ol>
191
192
193<!-- Designing Data Storage -->
194<h2 id="DataStorage">Mendesain Penyimpanan Data</h2>
195<p>
196    Penyedia konten adalah antarmuka ke data yang disimpan dalam format terstruktur. Sebelum membuat
197    antarmuka, Anda harus memutuskan cara menyimpan data. Anda bisa menyimpan data dalam bentuk apa saja yang Anda
198    sukai, kemudian mendesain antarmuka untuk membaca dan menulis data yang diperlukan.
199</p>
200<p>
201    Berikut ini adalah beberapa teknologi penyimpanan data yang tersedia di Android:
202</p>
203<ul>
204    <li>
205        Sistem Android menyertakan API database SQLite yang digunakan penyedia Android sendiri
206        untuk menyimpan data berorientasi tabel. Kelas
207        {@link android.database.sqlite.SQLiteOpenHelper} membantu Anda membuat database, dan kelas
208        {@link android.database.sqlite.SQLiteDatabase} adalah kelas dasar untuk mengakses
209        database.
210        <p>
211            Ingatlah bahwa Anda tidak harus menggunakan database untuk mengimplementasikan repository. Penyedia
212            muncul secara eksternal sebagai satu set tabel, yang serupa dengan sebuah database relasional, namun ini
213            bukan persyaratan untuk implementasi internal penyedia.
214        </p>
215    </li>
216    <li>
217        Untuk menyimpan file data, Android memiliki beragam API berorientasi file.
218        Untuk mengetahui selengkapnya tentang penyimpanan file, bacalah topik
219        <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a>. Jika Anda sedang
220        mendesain penyedia yang menawarkan data yang terkait dengan media seperti musik atau video, Anda bisa
221        memiliki penyedia yang mengombinasikan data tabel dan file.
222    </li>
223    <li>
224        Untuk bekerja dengan data berbasis jaringan, gunakan kelas-kelas dalam {@link java.net} dan
225        {@link android.net}. Anda juga bisa menyinkronkan data berbasis jaringan dengan penyimpanan data lokal
226        seperti database, kemudian menawarkan data sebagai tabel atau file.
227        Aplikasi contoh <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
228        Sample Sync Adapter</a> memperagakan tipe sinkronisasi ini.
229    </li>
230</ul>
231<h3 id="DataDesign">
232    Pertimbangan desain data
233</h3>
234<p>
235    Berikut ini adalah beberapa tip untuk mendesain struktur data penyedia:
236</p>
237<ul>
238    <li>
239        Data tabel harus selalu memiliki kolom "kunci utama" yang dipelihara oleh penyedia
240        sebagai nilai numerik unik untuk setiap baris. Anda bisa menggunakan nilai ini untuk menautkan baris ke
241        baris yang terkait dalam tabel lain (dengan menggunakannya sebagai "kunci asing"). Walaupun Anda bisa menggunakan nama
242        apa saja untuk kolom ini, menggunakan {@link android.provider.BaseColumns#_ID BaseColumns._ID} adalah
243        pilihan terbaik, karena menautkan hasil query penyedia dengan
244        {@link android.widget.ListView} mensyaratkan bahwa salah satu kolom yang diambil memiliki nama
245        <code>_ID</code>.
246    </li>
247    <li>
248        Jika Anda ingin untuk menyediakan gambar bitmap atau potongan data berorientasi file lainnya yang berukuran sangat besar, simpanlah
249        data dalam sebuah file kemudian sediakan secara tidak langsung sebagai ganti menyimpannya secara langsung dalam
250        tabel. Jika melakukannya, Anda perlu memberi tahu pengguna penyedia Anda bahwa mereka perlu menggunakan metode file
251        {@link android.content.ContentResolver} untuk mengakses data.
252    </li>
253    <li>
254        Gunakan tipe data Binary Large OBject (BLOB) untuk menyimpan data yang bervariasi ukurannya atau memiliki
255        struktur yang beragam. Misalnya, Anda bisa menggunakan sebuah kolom BLOB untuk menyimpan
256        <a href="http://code.google.com/p/protobuf">buffer protokol</a> atau
257        <a href="http://www.json.org">struktur JSON</a>.
258        <p>
259            Anda juga bisa menggunakan BLOB untuk mengimplementasikan tabel yang <em>tidak bergantung skema</em>. Dalam
260            tipe tabel ini, Anda mendefinisikan kolom kunci utama, kolom tipe MIME, dan satu atau beberapa
261            kolom generik sebagai BLOB. Arti dari data dalam kolom-kolom BLOB ditunjukkan
262            oleh nilai dalam kolom tipe MIME. Cara ini memungkinkan Anda menyimpan berbagai tipe baris dalam
263            tabel yang sama. Tabel "data"
264            {@link android.provider.ContactsContract.Data} Penyedia Kontak adalah contoh tabel yang tidak bergantung skema
265            tersebut.
266        </p>
267    </li>
268</ul>
269<!-- Designing Content URIs -->
270<h2 id="ContentURI">Mendesain URI Konten</h2>
271<p>
272    <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten
273    berisi nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah
274    nama yang menunjuk ke tabel atau file (<strong>path</strong>). Bagian id opsional menunjuk ke
275    satu baris dalam tabel. Setiap metode akses data
276    {@link android.content.ContentProvider} memiliki sebuah URI konten sebagai argumen; hal ini memungkinkan Anda
277    menentukan tabel, baris, atau file yang akan diakses.
278</p>
279<p>
280    Dasar-dasar URI konten dijelaskan dalam topik
281    <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
282    Dasar-Dasar Penyedia Konten</a>.
283</p>
284<h3>Mendesain otoritas</h3>
285<p>
286    Penyedia biasanya memiliki otoritas tunggal, yang berfungsi sebagai nama internal Android-nya. Untuk
287    menghindari konflik dengan penyedia lain, Anda harus menggunakan kepemilikan domain internet (secara terbalik)
288    sebagai basis otoritas penyedia Anda. Karena saran ini juga berlaku untuk
289    nama-nama paket Android, Anda bisa mendefinisikan otoritas penyedia sebagai perluasan dari nama
290    paket yang berisi penyedia. Misalnya, jika nama paket Android Anda adalah
291    <code>com.example.&lt;appname&gt;</code>, Anda harus memberikan penyedia Anda
292    otoritas <code>com.example.&lt;appname&gt;.provider</code>.
293</p>
294<h3>Mendesain struktur path</h3>
295<p>
296    Pengembang biasanya membuat URI konten dari otoritas dengan menambahkan path yang menunjuk ke
297    masing-masing tabel. Misalnya, jika Anda memiliki dua tabel <em>table1</em> dan
298    <em>table2</em>, Anda mengombinasikan otoritas dari contoh sebelumnya untuk menghasilkan
299    URI konten
300    <code>com.example.&lt;appname&gt;.provider/table1</code> dan
301    <code>com.example.&lt;appname&gt;.provider/table2</code>. Path tidak
302    dibatasi pada segmen tunggal, dan tidak harus berupa tabel untuk masing-masing tingkat path.
303</p>
304<h3>Menangani ID URI konten</h3>
305<p>
306    Berdasarkan standar, penyedia menawarkan akses ke satu baris dalam tabel dengan menerima URI konten
307    dengan sebuah nilai ID untuk baris itu di akhir URI. Juga berdasarkan standar, penyedia mencocokkan
308    nilai ID dengan kolom <code>_ID</code> tabel, dan melakukan akses yang diminta terhadap baris
309    yang cocok.
310</p>
311<p>
312    Standar ini memudahkan pola desain umum untuk aplikasi yang mengakses penyedia. Aplikasi
313    melakukan query terhadap penyedia dan menampilkan {@link android.database.Cursor} yang dihasilkan
314    dalam {@link android.widget.ListView} dengan menggunakan {@link android.widget.CursorAdapter}.
315    Definisi {@link android.widget.CursorAdapter} mengharuskan salah satu kolom dalam
316    {@link android.database.Cursor} berupa <code>_ID</code>
317</p>
318<p>
319    Pengguna kemudian mengambil salah satu baris yang ditampilkan dari UI untuk menemukan atau memodifikasi
320    data. Aplikasi mengambil baris yang sesuai dari {@link android.database.Cursor} yang mendukung
321    {@link android.widget.ListView}, mengambil nilai <code>_ID</code> untuk baris ini, menambahkannya ke
322    URI konten, dan mengirim permintaan akses ke penyedia. Penyedia nanti bisa melakukan
323    query atau modifikasi terhadap baris yang persis diambil pengguna.
324</p>
325<h3>Pola URI konten</h3>
326<p>
327    Untuk membantu Anda memilih tindakan yang diambil bagi URI konten yang masuk, API penyedia menyertakan
328    kelas praktis {@link android.content.UriMatcher}, yang memetakan "pola-pola" URI konten ke
329    nilai-nilai integer. Anda bisa menggunakan nilai-nilai integer dalam pernyataan <code>switch</code> yang
330    memilih tindakan yang diinginkan untuk URI konten atau URI yang cocok dengan pola tertentu.
331</p>
332<p>
333    Pola URI konten mencocokkan dengan URI konten menggunakan karakter wildcard:
334</p>
335    <ul>
336        <li>
337            <strong><code>*</code>:</strong> Mencocokkan string yang memiliki karakter yang sah dengan panjang berapa saja.
338        </li>
339        <li>
340            <strong><code>#</code>:</strong> Mencocokkan string karakter numerik dengan panjang berapa saja.
341        </li>
342    </ul>
343<p>
344    Sebagai contoh desain dan pemrograman penanganan URI konten, perhatikan penyedia dengan
345    otoritas <code>com.example.app.provider</code> yang mengenali URI konten berikut
346    yang menunjuk ke tabel-tabel:
347</p>
348<ul>
349    <li>
350        <code>content://com.example.app.provider/table1</code>: Tabel bernama <code>table1</code>.
351    </li>
352    <li>
353        <code>content://com.example.app.provider/table2/dataset1</code>: Tabel bernama
354        <code>dataset1</code>.
355    </li>
356    <li>
357        <code>content://com.example.app.provider/table2/dataset2</code>: Tabel bernama
358        <code>dataset2</code>.
359    </li>
360    <li>
361        <code>content://com.example.app.provider/table3</code>: Tabel bernama <code>table3</code>.
362    </li>
363</ul>
364<p>
365    Penyedia juga mengenali URI konten ini jika baris ID ditambahkan ke URI,
366    misalnya <code>content://com.example.app.provider/table3/1</code> untuk baris yang diidentifikasi oleh
367    <code>1</code> dalam <code>table3</code>.
368</p>
369<p>
370    Pola-pola URI konten berikut akan menjadi mungkin:
371</p>
372<dl>
373    <dt>
374        <code>content://com.example.app.provider/*</code>
375    </dt>
376    <dd>
377        Mencocokkan URI konten di penyedia.
378    </dd>
379    <dt>
380        <code>content://com.example.app.provider/table2/*</code>:
381    </dt>
382    <dd>
383        Mencocokkan URI konten untuk tabel-tabel <code>dataset1</code>
384        dan <code>dataset2</code>, namun tidak mencocokkan URI konten untuk <code>table1</code> atau
385        <code>table3</code>.
386    </dd>
387    <dt>
388        <code>content://com.example.app.provider/table3/#</code>: Mencocokkan URI konten
389        untuk satu baris di <code>table3</code>, misalnya
390        <code>content://com.example.app.provider/table3/6</code> untuk baris yang diidentifikasi oleh
391        <code>6</code>.
392    </dt>
393</dl>
394<p>
395    Cuplikan kode berikut menunjukkan cara kerja metode di {@link android.content.UriMatcher}.
396    Kode ini menangani URI seluruh tabel secara berbeda dengan URI untuk
397    satu baris, menggunakan pola URI konten
398    <code>content://&lt;authority&gt;/&lt;path&gt;</code> untuk tabel, dan
399    <code>content://&lt;authority&gt;/&lt;path&gt;/&lt;id&gt;</code> untuk satu baris.
400</p>
401<p>
402    Metode {@link android.content.UriMatcher#addURI(String, String, int) addURI()} memetakan
403    otoritas dan path ke nilai integer. Metode {@link android.content.UriMatcher#match(Uri)
404    match()} menghasilkan nilai integer URI. Pernyataan <code>switch</code>
405    memilih antara melakukan query seluruh tabel dan melakukan query satu record:
406</p>
407<pre class="prettyprint">
408public class ExampleProvider extends ContentProvider {
409...
410    // Creates a UriMatcher object.
411    private static final UriMatcher sUriMatcher;
412...
413    /*
414     * The calls to addURI() go here, for all of the content URI patterns that the provider
415     * should recognize. For this snippet, only the calls for table 3 are shown.
416     */
417...
418    /*
419     * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
420     * in the path
421     */
422    sUriMatcher.addURI("com.example.app.provider", "table3", 1);
423
424    /*
425     * Sets the code for a single row to 2. In this case, the "#" wildcard is
426     * used. "content://com.example.app.provider/table3/3" matches, but
427     * "content://com.example.app.provider/table3 doesn't.
428     */
429    sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
430...
431    // Implements ContentProvider.query()
432    public Cursor query(
433        Uri uri,
434        String[] projection,
435        String selection,
436        String[] selectionArgs,
437        String sortOrder) {
438...
439        /*
440         * Choose the table to query and a sort order based on the code returned for the incoming
441         * URI. Here, too, only the statements for table 3 are shown.
442         */
443        switch (sUriMatcher.match(uri)) {
444
445
446            // If the incoming URI was for all of table3
447            case 1:
448
449                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
450                break;
451
452            // If the incoming URI was for a single row
453            case 2:
454
455                /*
456                 * Because this URI was for a single row, the _ID value part is
457                 * present. Get the last path segment from the URI; this is the _ID value.
458                 * Then, append the value to the WHERE clause for the query
459                 */
460                selection = selection + "_ID = " uri.getLastPathSegment();
461                break;
462
463            default:
464            ...
465                // If the URI is not recognized, you should do some error handling here.
466        }
467        // call the code to actually do the query
468    }
469</pre>
470<p>
471    Kelas lainnya, {@link android.content.ContentUris}, menyediakan metode praktis untuk menggunakan
472    bagian <code>id</code> URI konten. Kelas-kelas {@link android.net.Uri} dan
473    {@link android.net.Uri.Builder} menyertakan metode praktis untuk mengurai
474    objek {@link android.net.Uri} yang ada dan membuat objek baru.
475</p>
476
477<!-- Implementing the ContentProvider class -->
478<h2 id="ContentProvider">Mengimplementasikan Kelas ContentProvider</h2>
479<p>
480    Instance {@link android.content.ContentProvider} mengelola akses
481    ke satu set data terstruktur dengan menangani permintaan dari aplikasi lain. Semua bentuk
482    akses pada akhirnya akan memanggil {@link android.content.ContentResolver}, yang kemudian memanggil
483    metode konkret {@link android.content.ContentProvider} untuk mendapatkan akses.
484</p>
485<h3 id="RequiredAccess">Metode-metode yang diperlukan</h3>
486<p>
487    Kelas abstrak {@link android.content.ContentProvider} mendefinisikan enam metode abstrak yang
488    harus Anda implementasikan sebagai bagian dari subkelas konkret Anda sendiri. Semua metode ini kecuali
489    {@link android.content.ContentProvider#onCreate() onCreate()} dipanggil oleh aplikasi klien
490    yang berupaya mengakses penyedia konten Anda:
491</p>
492<dl>
493    <dt>
494        {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
495        query()}
496    </dt>
497    <dd>
498        Mengambil data dari penyedia Anda. Menggunakan argumen untuk memilih tabel yang akan
499        di-query, baris dan kolom yang akan dihasilkan, dan urutan sortir hasilnya.
500        Menghasilkan data berupa objek {@link android.database.Cursor}.
501    </dd>
502    <dt>
503        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}
504    </dt>
505    <dd>
506        Menyisipkan baris baru ke dalam penyedia Anda. Menggunakan argumen untuk memilih
507        tabel tujuan dan mendapatkan nilai-nilai kolom yang akan digunakan. Menghasilkan URI konten untuk
508        baris yang baru disisipkan.
509    </dd>
510    <dt>
511        {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
512        update()}
513    </dt>
514    <dd>
515        Memperbarui baris yang ada di penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris
516        yang akan diperbarui dan mendapatkan nilai-nilai kolom yang diperbarui. Menghasilkan jumlah baris yang diperbarui.
517    </dd>
518    <dt>
519        {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
520    </dt>
521    <dd>
522        Menghapus baris dari penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris yang akan
523        dihapus. Menghasilkan jumlah baris yang dihapus.
524    </dd>
525    <dt>
526        {@link android.content.ContentProvider#getType(Uri) getType()}
527    </dt>
528    <dd>
529        Menghasilkan tipe MIME yang sesuai dengan URI konten. Metode ini dijelaskan lebih detail
530        di bagian <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>.
531    </dd>
532    <dt>
533        {@link android.content.ContentProvider#onCreate() onCreate()}
534    </dt>
535    <dd>
536        Inisialisasi penyedia Anda. Sistem Android memanggil metode ini segera setelah
537        membuat penyedia Anda. Perhatikan bahwa penyedia Anda tidak dibuat hingga
538        objek {@link android.content.ContentResolver} mencoba mengaksesnya.
539    </dd>
540</dl>
541<p>
542    Perhatikan bahwa metode-metode ini memiliki signature yang sama dengan
543    metode-metode {@link android.content.ContentResolver} yang sama namanya.
544</p>
545<p>
546    Implementasi metode-metode ini harus memperhitungkan hal-hal berikut:
547</p>
548<ul>
549    <li>
550        Semua metode ini kecuali {@link android.content.ContentProvider#onCreate() onCreate()}
551        bisa dipanggil oleh beberapa thread sekaligus, jadi harus thread-safe (aman untuk thread). Untuk mengetahui
552        selengkapnya tentang multi-thread, lihat topik
553        <a href="{@docRoot}guide/components/processes-and-threads.html">
554        Proses dan Thread</a>.
555    </li>
556    <li>
557        Hindari melakukan operasi yang lama dalam {@link android.content.ContentProvider#onCreate()
558        onCreate()}. Tunda inisialisasi tugas hingga benar-benar diperlukan.
559        Bagian <a href="#OnCreate">Mengimplementasikan metode onCreate()</a>
560        membahas hal ini secara lebih detail.
561    </li>
562    <li>
563        Walaupun harus mengimplementasikan metode-metode ini, kode Anda tidak harus melakukan apa pun selain
564        tipe data yang diharapkan. Misalnya, Anda mungkin ingin mencegah aplikasi lain
565        menyisipkan data ke dalam beberapa tabel. Caranya, Anda bisa mengabaikan panggilan ke
566        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} dan menghasilkan
567        0.
568    </li>
569</ul>
570<h3 id="Query">Mengimplementasikan metode query()</h3>
571<p>
572    Metode
573    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
574    ContentProvider.query()} harus menghasilkan objek {@link android.database.Cursor}, atau jika
575    gagal, melontarkan {@link java.lang.Exception}. Jika menggunakan database SQLite sebagai
576    penyimpanan data, Anda bisa mengembalikan{@link android.database.Cursor} yang dikembalikan oleh salah satu metode
577    <code>query()</code> dari kelas {@link android.database.sqlite.SQLiteDatabase}.
578    Jika query tidak mencocokkan baris apa pun, Anda harus mengembalikan instance {@link android.database.Cursor}
579    yang metode {@link android.database.Cursor#getCount()}-nya mengembalikan 0.
580    Anda harus mengembalikan <code>null</code> hanya jika terjadi kesalahan internal selama proses query.
581</p>
582<p>
583    Jika Anda tidak menggunakan database SQLite sebagai penyimpanan data, gunakan salah satu subkelas konkret
584    {@link android.database.Cursor}. Misalnya, kelas {@link android.database.MatrixCursor}
585    mengimplementasikan kursor dengan masing-masing baris berupa larik {@link java.lang.Object}. Dengan kelas ini,
586    gunakan {@link android.database.MatrixCursor#addRow(Object[]) addRow()} untuk menambahkan baris baru.
587</p>
588<p>
589    Ingatlah bahwa sistem Android harus mampu mengomunikasikan {@link java.lang.Exception}
590    lintas batas proses. Android bisa melakukannya untuk eksepsi berikut yang mungkin berguna
591    dalam menangani kesalahan query:
592</p>
593<ul>
594    <li>
595        {@link java.lang.IllegalArgumentException} (Anda bisa saja melontarkannya jika penyedia Anda
596        menerima URI konten yang tidak sah)
597    </li>
598    <li>
599        {@link java.lang.NullPointerException}
600    </li>
601</ul>
602<h3 id="Insert">Mengimplementasikan metode insert()</h3>
603<p>
604    Metode {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} menambahkan satu
605    baris baru ke tabel yang sesuai, dengan menggunakan nilai-nilai dalam argumen {@link android.content.ContentValues}.
606 Jika kolom nama tidak ada dalam argumen {@link android.content.ContentValues}, Anda
607    mungkin perlu menyediakan nilai default untuknya, baik dalam kode penyedia atau dalam skema database
608    Anda.
609</p>
610<p>
611    Metode ini harus mengembalikan URI konten untuk baris baru. Untuk membuatnya, tambahkan nilai
612    <code>_ID</code> baris baru (atau kunci utama lainnya) ke tabel URI konten, dengan menggunakan
613    {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}.
614</p>
615<h3 id="Delete">Mengimplementasikan metode delete()</h3>
616<p>
617    Metode {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
618    tidak harus menghapus baris-baris dari penyimpanan data Anda secara fisik. Jika menggunakan adaptor sinkronisasi
619    bersama penyedia, Anda harus mempertimbangkan penandaan baris yang dihapus
620    dengan flag "delete"; bukan menghilangkan baris itu sepenuhnya. Adaptor sinkronisasi bisa
621    memeriksa baris yang dihapus dan menghilangkannya dari server sebelum menghapusnya dari penyedia.
622</p>
623<h3 id="Update">Mengimplementasikan metode update()</h3>
624<p>
625    Metode {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
626    update()} mengambil argumen {@link android.content.ContentValues} yang sama dengan yang digunakan oleh
627    {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, dan
628    argumen-argumen <code>selection</code> dan <code>selectionArgs</code> yang sama dengan yang digunakan oleh
629    {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} dan
630    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
631    ContentProvider.query()}. Hal ini bisa memungkinkan Anda menggunakan kembali kode di antara metode-metode ini.
632</p>
633<h3 id="OnCreate">Mengimplementasikan metode onCreate()</h3>
634<p>
635    Sistem Android memanggil {@link android.content.ContentProvider#onCreate()
636    onCreate()} saat memulai penyedia. Anda harus melakukan tugas-tugas inisialisasi yang berjalan cepat saja
637    dalam metode ini, serta menunda pembuatan database dan pemuatan data hingga penyedia benar-benar
638    menerima permintaan terhadap data. Jika Anda melakukan tugas yang memakan waktu dalam
639    {@link android.content.ContentProvider#onCreate() onCreate()}, Anda akan memperlambat
640    startup penyedia. Pada gilirannya, hal ini akan memperlambat respons dari penyedia terhadap
641    aplikasi lain.
642</p>
643<p>
644    Misalnya, jika menggunakan database SQLite, Anda bisa membuat
645    sebuah objek {@link android.database.sqlite.SQLiteOpenHelper} baru di
646    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()},
647    kemudian membuat tabel-tabel SQL saat pertama kali membuka database itu. Untuk memperlancar hal ini,
648    saat pertama Anda memanggil {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase
649    getWritableDatabase()}, metode ini memanggil metode
650    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
651    SQLiteOpenHelper.onCreate()} secara otomatis.
652</p>
653<p>
654    Dua cuplikan berikut memperagakan interaksi antara
655    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} dan
656    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
657    SQLiteOpenHelper.onCreate()}. Cuplikan pertama adalah implementasi
658    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}:
659</p>
660<pre class="prettyprint">
661public class ExampleProvider extends ContentProvider
662
663    /*
664     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
665     * in a following snippet.
666     */
667    private MainDatabaseHelper mOpenHelper;
668
669    // Defines the database name
670    private static final String DBNAME = "mydb";
671
672    // Holds the database object
673    private SQLiteDatabase db;
674
675    public boolean onCreate() {
676
677        /*
678         * Creates a new helper object. This method always returns quickly.
679         * Notice that the database itself isn't created or opened
680         * until SQLiteOpenHelper.getWritableDatabase is called
681         */
682        mOpenHelper = new MainDatabaseHelper(
683            getContext(),        // the application context
684            DBNAME,              // the name of the database)
685            null,                // uses the default SQLite cursor
686            1                    // the version number
687        );
688
689        return true;
690    }
691
692    ...
693
694    // Implements the provider's insert method
695    public Cursor insert(Uri uri, ContentValues values) {
696        // Insert code here to determine which table to open, handle error-checking, and so forth
697
698        ...
699
700        /*
701         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
702         *
703         */
704        db = mOpenHelper.getWritableDatabase();
705    }
706}
707</pre>
708<p>
709    Cuplikan berikutnya adalah implementasi
710    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
711    SQLiteOpenHelper.onCreate()}, yang menyertakan kelas helper:
712</p>
713<pre class="prettyprint">
714...
715// A string that defines the SQL statement for creating a table
716private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
717    "main " +                       // Table's name
718    "(" +                           // The columns in the table
719    " _ID INTEGER PRIMARY KEY, " +
720    " WORD TEXT"
721    " FREQUENCY INTEGER " +
722    " LOCALE TEXT )";
723...
724/**
725 * Helper class that actually creates and manages the provider's underlying data repository.
726 */
727protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
728
729    /*
730     * Instantiates an open helper for the provider's SQLite data repository
731     * Do not do database creation and upgrade here.
732     */
733    MainDatabaseHelper(Context context) {
734        super(context, DBNAME, null, 1);
735    }
736
737    /*
738     * Creates the data repository. This is called when the provider attempts to open the
739     * repository and SQLite reports that it doesn't exist.
740     */
741    public void onCreate(SQLiteDatabase db) {
742
743        // Creates the main table
744        db.execSQL(SQL_CREATE_MAIN);
745    }
746}
747</pre>
748
749
750<!-- Implementing ContentProvider MIME Types -->
751<h2 id="MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</h2>
752<p>
753    Kelas {@link android.content.ContentProvider} memiliki dua metode untuk menghasilkan tipe-tipe MIME:
754</p>
755<dl>
756    <dt>
757        {@link android.content.ContentProvider#getType(Uri) getType()}
758    </dt>
759    <dd>
760        Salah satu metode wajib yang harus Anda implementasikan untuk setiap penyedia.
761    </dd>
762    <dt>
763        {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
764    </dt>
765    <dd>
766        Sebuah metode yang diharapkan untuk Anda implementasikan jika penyedia Anda menawarkan file.
767    </dd>
768</dl>
769<h3 id="TableMIMETypes">Tipe MIME untuk tabel</h3>
770<p>
771    Metode {@link android.content.ContentProvider#getType(Uri) getType()} mengembalikan
772    {@link java.lang.String} dengan format MIME yang menjelaskan tipe data yang dikembalikan oleh
773    argumen URI konten. Argumen {@link android.net.Uri} bisa berupa pola, bukannya URI tertentu;
774    dalam hal ini, Anda harus mengembalikan tipe data terkait URI konten yang cocok dengan
775    polanya.
776</p>
777<p>
778    Untuk tipe data umum misalnya teks, HTML, atau JPEG,
779    {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan
780    tipe MIME standar untuk data itu. Daftar lengkap tipe standar ini tersedia di situs web
781    <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a>.
782
783</p>
784<p>
785    Untuk URI konten yang menunjuk ke baris atau baris-baris data tabel,
786    {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan
787    tipe MIME dalam format MIME khusus vendor Android:
788</p>
789<ul>
790    <li>
791        Bagian tipe: <code>vnd</code>
792    </li>
793    <li>
794        Bagian subtipe:
795        <ul>
796            <li>
797    Jika pola URI adalah untuk satu baris: <code>android.cursor.<strong>item</strong>/</code>
798            </li>
799            <li>
800    Jika pola URI adalah untuk lebih dari satu baris: <code>android.cursor.<strong>dir</strong>/</code>
801            </li>
802        </ul>
803    </li>
804    <li>
805        Bagian khusus penyedia: <code>vnd.&lt;name&gt;</code>.<code>&lt;type&gt;</code>
806        <p>
807            Anda menyediakan <code>&lt;name&gt;</code> dan <code>&lt;type&gt;</code>.
808            Nilai <code>&lt;name&gt;</code> harus unik secara global,
809            dan nilai <code>&lt;type&gt;</code> harus unik bagi pola URI
810            yang sesuai. Pilihan tepat untuk <code>&lt;name&gt;</code> adalah nama perusahaan Anda atau
811            sebagian dari nama paket Android aplikasi Anda. Pilihan tepat untuk
812            <code>&lt;type&gt;</code> adalah string yang mengidentifikasi tabel yang terkait dengan
813            URI.
814        </p>
815
816    </li>
817</ul>
818<p>
819    Misalnya, jika otoritas penyedia adalah
820    <code>com.example.app.provider</code>, dan penyedia mengekspos tabel bernama
821    <code>table1</code>, tipe MIME untuk beberapa baris dalam <code>table1</code> adalah:
822</p>
823<pre>
824vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1
825</pre>
826<p>
827    Untuk satu baris <code>table1</code>, tipe MIME adalah:
828</p>
829<pre>
830vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1
831</pre>
832<h3 id="FileMIMETypes">Tipe MIME untuk file</h3>
833<p>
834    Jika penyedia Anda menawarkan file, implementasikan
835    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}.
836    Metode ini menghasilkan larik {@link java.lang.String} tipe MIME untuk file
837    yang bisa dikembalikan penyedia Anda untuk URI konten bersangkutan. Anda harus memfilter tipe MIME yang Anda tawarkan dengan argumen filter
838    tipe MIME, sehingga Anda hanya mengembalikan tipe MIME yang ingin ditangani klien.
839</p>
840<p>
841    Misalnya, perhatikan penyedia yang menawarkan gambar foto sebagai file dalam format <code>.jpg</code>,
842    <code>.png</code>, dan <code>.gif</code>.
843    Jika aplikasi memanggil {@link android.content.ContentResolver#getStreamTypes(Uri, String)
844    ContentResolver.getStreamTypes()} dengan string filter <code>image/*</code> (sesuatu yang
845    merupakan "gambar"),
846    maka metode {@link android.content.ContentProvider#getStreamTypes(Uri, String)
847    ContentProvider.getStreamTypes()} harus mengembalikan larik:
848</p>
849<pre>
850{ &quot;image/jpeg&quot;, &quot;image/png&quot;, &quot;image/gif&quot;}
851</pre>
852<p>
853    Jika aplikasi tertarik pada file <code>.jpg</code>, maka aplikasi bisa memanggil
854    {@link android.content.ContentResolver#getStreamTypes(Uri, String)
855    ContentResolver.getStreamTypes()} dengan string filter <code>*\/jpeg</code>, dan
856    {@link android.content.ContentProvider#getStreamTypes(Uri, String)
857    ContentProvider.getStreamTypes()} harus mengembalikan:
858<pre>
859{&quot;image/jpeg&quot;}
860</pre>
861<p>
862    Jika penyedia Anda tidak menawarkan tipe MIME apa pun yang diminta dalam string filter,
863    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
864    harus mengembalikan <code>null</code>.
865</p>
866
867
868<!--  Implementing a Contract Class -->
869<h2 id="ContractClass">Mengimplementasikan Kelas Kontrak</h2>
870<p>
871    Kelas kontrak adalah kelas <code>public final</code> yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan
872metadata lain yang melekat ke penyedia. Kelas
873    membentuk sebuah kontrak antara penyedia dan aplikasi lain dengan memastikan bahwa penyedia
874    bisa diakses dengan benar sekalipun ada perubahan pada nilai URI sesungguhnya, nama kolom,
875    dan seterusnya.
876</p>
877<p>
878    Kelas kontrak juga membantu pengembang karena kelas ini biasanya memiliki nama-nama simbolik untuk konstantanya,
879    sehingga memperkecil kemungkinan pengembang menggunakan nilai yang salah untuk nama kolom atau URI. Karena berupa
880    kelas, kelas ini bisa berisi dokumentasi Javadoc. Lingkungan pengembangan terpadu (IDE) seperti
881    Eclipse secara otomatis bisa melengkapi nama-nama konstanta dari kelas kontrak dan menampilkan Javadoc untuk
882    konstanta.
883</p>
884<p>
885    Pengembang tidak bisa mengakses file kelas milik kelas kontrak dari aplikasi Anda, namun bisa
886    mengompilasinya secara statis ke dalam aplikasi mereka dari file <code>.jar</code> yang Anda sediakan.
887</p>
888<p>
889    Kelas {@link android.provider.ContactsContract} dan kelas-kelas tersarangnya adalah contoh
890    kelas kontrak.
891</p>
892<h2 id="Permissions">Mengimplementasikan Izin Penyedia Konten</h2>
893<p>
894    Izin dan akses untuk semua aspek sistem Android dijelaskan secara detail dalam
895    topik <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>.
896    Topik <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a> juga
897    menjelaskan keamanan dan izin terkait dengan berbagai tipe penyimpanan.
898    Singkatnya, poin-poin pentingnya adalah:
899</p>
900<ul>
901    <li>
902        Secara default, file data yang disimpan pada penyimpanan internal perangkat bersifat privat bagi
903        aplikasi dan penyedia Anda.
904    </li>
905    <li>
906        Database {@link android.database.sqlite.SQLiteDatabase} yang Anda buat bersifat privat bagi
907        aplikasi dan penyedia Anda.
908    </li>
909    <li>
910        Secara default, file data yang Anda simpan ke penyimpanan eksternal bersifat <em>publik</em> dan
911        <em>bisa dibaca secara global</em>. Anda tidak bisa menggunakan penyedia konten untuk membatasi akses ke file dalam
912        penyimpanan eksternal, karena aplikasi lain bisa menggunakan panggilan API untuk membaca dan menulis ke file tersebut.
913    </li>
914    <li>
915        Panggilan metode untuk membuka atau membuat file atau database SQLite pada
916        penyimpanan internal perangkat Anda berpotensi memberikan akses baca maupun tulis ke semua aplikasi lain. Jika Anda
917        menggunakan file atau database internal sebagai repository penyedia, dan Anda memberinya
918        akses "world-readable" (bisa dibaca secara global) atau "world-writeable" (bisa ditulis secara global), izin yang Anda atur untuk penyedia dalam
919        manifesnya tidak akan melindungi data Anda. Akses default untuk file dan database dalam
920        penyimpanan internal adalah "privat", dan untuk repository penyedia, tidak boleh Anda ubah.
921    </li>
922</ul>
923<p>
924    Jika Anda ingin menggunakan izin penyedia konten untuk mengontrol akses ke data Anda, maka Anda harus
925    menyimpan data Anda dalam file internal, database SQLite, atau "cloud" (misalnya,
926    di server jauh), dan Anda harus membuat file dan database tetap privat bagi aplikasi Anda.
927</p>
928<h3>Mengimplementasikan izin</h3>
929<p>
930    Semua aplikasi bisa membaca dari atau menulis ke penyedia Anda, sekalipun data yang mendasari adalah
931    privat, karena secara default penyedia Anda tidak mengatur izin. Untuk mengubahnya,
932    atur izin untuk penyedia dalam file manifes, dengan menggunakan atribut atau elemen anak
933    dari elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
934    &lt;provider&gt;</a></code>. Anda bisa mengatur izin yang berlaku pada seluruh penyedia,
935    atau pada tabel tertentu, atau bahkan pada record tertentu, atau ketiganya.
936</p>
937<p>
938    Anda mendefinisikan izin untuk penyedia dengan satu atau beberapa elemen
939    <code><a href="{@docRoot}guide/topics/manifest/permission-element.html">
940    &lt;permission&gt;</a></code> dalam file manifes. Untuk membuat
941    izin unik bagi penyedia, gunakan scoping (pengaturan lingkup) bergaya Java untuk
942    atribut <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm">
943    android:name</a></code>. Misalnya, beri nama izin membaca dengan
944    <code>com.example.app.provider.permission.READ_PROVIDER</code>.
945
946</p>
947<p>
948    Daftar berikut menjelaskan lingkup penyedia izin, mulai dengan
949    izin yang berlaku pada seluruh penyedia kemudian menjadi semakin sempit.
950    Izin yang lebih sempit akan didahulukan daripada izin yang berlingkup lebih luas:
951</p>
952<dl>
953    <dt>
954        Izin baca-tulis tunggal tingkat penyedia
955    </dt>
956    <dd>
957        Suatu izin yang mengontrol akses baca-tulis bagi seluruh penyedia, ditetapkan
958        dengan atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
959        android:permission</a></code> dari
960        elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
961        &lt;provider&gt;</a></code>.
962    </dd>
963    <dt>
964        Izin baca-tulis terpisah tingkat penyedia
965    </dt>
966    <dd>
967        Satu izin baca dan satu izin tulis untuk seluruh penyedia. Anda menetapkan keduanya
968        dengan atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
969        android:readPermission</a></code> dan
970        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
971        android:writePermission</a></code> dari elemen
972        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
973        &lt;provider&gt;</a></code>. Kedua izin akan didahulukan daripada izin yang diharuskan oleh
974        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
975        android:permission</a></code>.
976    </dd>
977    <dt>
978        Izin tingkat path
979    </dt>
980    <dd>
981        Izin baca, tulis, atau baca/tulis untuk URI konten dalam penyedia Anda. Anda menetapkan
982        tiap URI yang ingin dikontrol dengan elemen anak
983        <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html">
984        &lt;path-permission&gt;</a></code> dari
985        elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
986        &lt;provider&gt;</a></code>. Untuk setiap URI konten yang ditetapkan, Anda bisa menetapkan
987        satu izin baca/tulis, satu izin baca, atau satu izin tulis, atau ketiganya. Izin baca dan
988        tulis akan didahulukan daripada izin baca/tulis. Juga,
989        izin tingkat path akan didahulukan daripada izin tingkat penyedia.
990    </dd>
991    <dt>
992        Izin sementara
993    </dt>
994    <dd>
995        Tingkat izin yang memberikan akses sementara ke aplikasi, sekalipun aplikasi itu
996        tidak memiliki izin yang biasanya diminta. Fitur akses
997         sementara mengurangi jumlah izin yang harus diminta aplikasi dalam
998        manifesnya. Bila Anda mengaktifkan izin sementara, satu-satunya aplikasi yang memerlukan
999        izin "permanen" untuk penyedia adalah aplikasi yang mengakses terus-menerus semua
1000        data Anda.
1001        <p>
1002            Perhatikan izin yang Anda perlukan untuk mengimplementasikan penyedia dan aplikasi email, bila Anda
1003            ingin memperbolehkan aplikasi penampil gambar dari luar menampilkan lampiran foto dari
1004            penyedia Anda. Untuk memberikan akses yang diperlukan kepada penampil gambar tanpa mengharuskan izin,
1005            siapkan izin sementara untuk URI konten bagi foto. Desainlah aplikasi email Anda agar
1006            bila pengguna ingin menampilkan foto, aplikasi itu akan mengirim intent berisi
1007            URI konten foto dan flag izin ke penampil gambar. Penampil gambar nanti bisa
1008            melakukan query penyedia email untuk mengambil foto, sekalipun penampil itu tidak
1009            memiliki izin baca normal untuk penyedia Anda.
1010        </p>
1011        <p>
1012            Untuk mengaktifkan izin sementara, atur atribut
1013            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
1014            android:grantUriPermissions</a></code> dari
1015            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
1016            &lt;provider&gt;</a></code>, atau tambahkan satu atau beberapa elemen anak
1017            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
1018            &lt;grant-uri-permission&gt;</a></code> ke
1019            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
1020            &lt;provider&gt;</a></code> Anda. Jika menggunakan izin sementara, Anda harus memanggil
1021            {@link android.content.Context#revokeUriPermission(Uri, int)
1022            Context.revokeUriPermission()} kapan saja Anda menghilangkan dukungan untuk URI konten dari
1023            penyedia, dan URI konten dikaitkan dengan izin sementara.
1024        </p>
1025        <p>
1026            Nilai atribut menentukan seberapa banyak penyedia Anda yang dijadikan bisa diakses.
1027            Jika atribut diatur ke <code>true</code>, maka sistem akan memberikan
1028            izin sementara kepada seluruh penyedia, dengan mengesampingkan izin lain yang diharuskan
1029            oleh izin tingkat penyedia atau tingkat path.
1030        </p>
1031        <p>
1032            Jika flag ini diatur ke <code>false</code>, maka Anda harus menambahkan elemen-elemen anak
1033            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
1034            &lt;grant-uri-permission&gt;</a></code> ke
1035            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
1036            &lt;provider&gt;</a></code> Anda. Tiap elemen anak menetapkan URI konten atau
1037            URI yang telah diberi akses sementara.
1038        </p>
1039        <p>
1040            Untuk mendelegasikan akses sementara ke sebuah aplikasi, intent harus berisi
1041            {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} atau flag
1042            {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, atau keduanya. Keduanya
1043            diatur dengan metode {@link android.content.Intent#setFlags(int) setFlags()}.
1044        </p>
1045        <p>
1046            Jika atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
1047            android:grantUriPermissions</a></code> tidak ada, atribut ini diasumsikan sebagai
1048            <code>false</code>.
1049        </p>
1050    </dd>
1051</dl>
1052
1053
1054
1055<!-- The Provider Element -->
1056<h2 id="ProviderElement">Elemen &lt;provider&gt;</h2>
1057<p>
1058    Seperti halnya komponen {@link android.app.Activity} dan {@link android.app.Service},
1059    subkelas {@link android.content.ContentProvider}
1060    harus didefinisikan dalam file manifes untuk aplikasinya, dengan menggunakan elemen
1061    <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
1062    &lt;provider&gt;</a></code>. Sistem Android mendapatkan informasi berikut dari
1063    elemen:
1064<dl>
1065    <dt>
1066        Otoritas
1067        (<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code
1068        android:authorities}</a>)
1069    </dt>
1070    <dd>
1071        Nama-nama simbolik yang mengidentifikasi seluruh penyedia dalam sistem. Atribut
1072        ini dijelaskan lebih detail di bagian
1073        <a href="#ContentURI">Mendesain URI Konten</a>.
1074    </dd>
1075    <dt>
1076        Nama kelas penyedia
1077        (<code>
1078<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a>
1079        </code>)
1080    </dt>
1081    <dd>
1082        Kelas yang mengimplementasikan {@link android.content.ContentProvider}. Kelas ini
1083        dijelaskan lebih detail di bagian
1084        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>.
1085    </dd>
1086    <dt>
1087        Izin
1088    </dt>
1089    <dd>
1090        Atribut-atribut yang menetapkan izin yang harus dimiliki aplikasi lain untuk mengakses
1091        data penyedia:
1092        <ul>
1093            <li>
1094                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
1095                android:grantUriPermssions</a></code>: Flag izin sementara.
1096            </li>
1097            <li>
1098                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
1099                android:permission</a></code>: Izin baca/tulis tunggal untuk tingkat penyedia.
1100            </li>
1101            <li>
1102                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
1103                android:readPermission</a></code>: Izin baca untuk tingkat penyedia.
1104            </li>
1105            <li>
1106                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
1107                android:writePermission</a></code>: Izin tulis untuk tingkat penyedia.
1108            </li>
1109        </ul>
1110        <p>
1111            Izin dan atribut-atribut yang sesuai dijelaskan lebih detail
1112            di bagian
1113            <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a>.
1114        </p>
1115    </dd>
1116    <dt>
1117        Atribut-atribut startup dan kontrol
1118    </dt>
1119    <dd>
1120        Atribut-atribut ini menentukan cara dan waktu sistem Android memulai penyedia,
1121        karakteristik proses penyedia, dan pengaturan runtime lainnya:
1122        <ul>
1123            <li>
1124                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled">
1125                android:enabled</a></code>: Flag yang memperbolehkan sistem untuk memulai penyedia.
1126            </li>
1127              <li>
1128                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
1129                android:exported</a></code>: Flag yang memperbolehkan aplikasi lain untuk menggunakan penyedia ini.
1130            </li>
1131            <li>
1132                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init">
1133                android:initOrder</a></code>: Urutan yang digunakan untuk memulai penyedia ini,
1134                relatif terhadap penyedia lain dalam proses yang sama.
1135            </li>
1136            <li>
1137                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi">
1138                android:multiProcess</a></code>: Flag yang memperbolehkan sistem untuk memulai penyedia
1139                dalam proses yang sama dengan proses klien pemanggil.
1140            </li>
1141            <li>
1142                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc">
1143                android:process</a></code>: Nama proses tempat penyedia harus
1144                berjalan.
1145            </li>
1146            <li>
1147                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync">
1148                android:syncable</a></code>: Flag yang menunjukkan bahwa data penyedia harus
1149                disinkronkan dengan data di server.
1150            </li>
1151        </ul>
1152        <p>
1153            Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen
1154            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
1155            &lt;provider&gt;</a></code>.
1156
1157        </p>
1158    </dd>
1159    <dt>
1160        Atribut-atribut informatif
1161    </dt>
1162    <dd>
1163        Ikon dan label opsional untuk penyedia:
1164        <ul>
1165            <li>
1166                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon">
1167                android:icon</a></code>: Sumber daya drawable, berisi ikon untuk penyedia.
1168                Ikon ini muncul di sebelah label penyedia dalam daftar aplikasi dalam menu
1169                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
1170            </li>
1171            <li>
1172                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label">
1173                android:label</a></code>: Label informatif yang menjelaskan penyedia atau
1174                datanya, atau keduanya. Label ini muncul dalam daftar aplikasi di
1175                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
1176            </li>
1177        </ul>
1178        <p>
1179            Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen
1180            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
1181            &lt;provider&gt;</a></code>.
1182        </p>
1183    </dd>
1184</dl>
1185
1186<!-- Intent Access -->
1187<h2 id="Intents">Intent dan Akses Data</h2>
1188<p>
1189    Aplikasi bisa mengakses penyedia konten secara tidak langsung dengan sebuah {@link android.content.Intent}.
1190    Aplikasi tidak memanggil satu pun dari metode-metode {@link android.content.ContentResolver} atau
1191    {@link android.content.ContentProvider}. Sebagai gantinya, aplikasi mengirim intent yang memulai aktivitas,
1192    yang sering kali merupakan bagian dari aplikasi penyedia sendiri. Aktivitas tujuan bertugas
1193    mengambil dan menampilkan data dalam UI-nya. Bergantung pada tindakan dalam intent,
1194    aktivitas tujuan juga bisa meminta pengguna untuk membuat modifikasi pada data penyedia.
1195    Intent juga bisa berisi data "ekstra" yang menampilkan aktivitas tujuan
1196    dalam UI; pengguna nanti memiliki pilihan untuk mengubah data ini sebelum menggunakannya untuk mengubah
1197    data di penyedia.
1198</p>
1199<p>
1200
1201</p>
1202<p>
1203    Anda mungkin perlu menggunakan akses intent guna membantu memastikan integritas data. Penyedia Anda mungkin bergantung
1204    pada data yang disisipkan, diperbarui, dan dihapusnya sesuai dengan logika bisnis yang didefinisikan dengan ketat. Jika
1205    demikian halnya, memperbolehkan aplikasi lain mengubah data Anda secara langsung bisa menyebabkan
1206    data yang tidak sah. Jika Anda ingin pengembang menggunakan akses intent, pastikan untuk mendokumentasikannya secara saksama.
1207    Jelaskan kepada mereka alasan akses intent yang menggunakan UI aplikasi Anda sendiri adalah lebih baik daripada mencoba
1208    memodifikasi data dengan kode mereka.
1209</p>
1210<p>
1211    Menangani sebuah intent masuk yang ingin memodifikasi data penyedia Anda tidak berbeda dengan
1212    menangani intent lainnya. Anda bisa mengetahui selengkapnya tentang penggunaan intent dengan membaca topik
1213    <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
1214</p>
1215