Home | History | Annotate | Download | only in providers
      1 page.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">
    408 public 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">
    661 public 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
    716 private 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  */
    727 protected 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>
    824 vnd.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>
    830 vnd.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
    872 metadata 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