1page.title=Dasar-Dasar Penyedia Konten 2@jd:body 3<div id="qv-wrapper"> 4<div id="qv"> 5<!-- In this document --> 6<h2>Dalam dokumen ini</h2> 7<ol> 8 <li> 9 <a href="#Basics">Ikhtisar</a> 10 <ol> 11 <li> 12 <a href="#ClientProvider">Mengakses penyedia</a> 13 </li> 14 <li> 15 <a href="#ContentURIs">URI Konten</a> 16 </li> 17 </ol> 18 </li> 19 <li> 20 <a href="#SimpleQuery">Mengambil Data dari Penyedia</a> 21 <ol> 22 <li> 23 <a href="#RequestPermissions">Meminta izin akses baca</a> 24 </li> 25 <li> 26 <a href="#Query">Membuat query</a> 27 </li> 28 <li> 29 <a href="#DisplayResults">Menampilkan hasil query</a> 30 </li> 31 <li> 32 <a href="#GettingResults">Mendapatkan data dari hasil query</a> 33 </li> 34 </ol> 35 </li> 36 <li> 37 <a href="#Permissions">Izin Penyedia Konten</a> 38 </li> 39 <li> 40 <a href="#Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</a> 41 <ol> 42 <li> 43 <a href="#Inserting">Menyisipkan data</a> 44 </li> 45 <li> 46 <a href="#Updating">Memperbarui data</a> 47 </li> 48 <li> 49 <a href="#Deleting">Menghapus data</a> 50 </li> 51 </ol> 52 </li> 53 <li> 54 <a href="#DataTypes">Tipe Data Penyedia</a> 55 </li> 56 <li> 57 <a href="#AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</a> 58 <ol> 59 <li> 60 <a href="#Batch">Akses batch</a> 61 </li> 62 <li> 63 <a href="#Intents">Akses data melalui intent</a> 64 </li> 65 </ol> 66 </li> 67 <li> 68 <a href="#ContractClasses">Kelas-kelas Kontrak</a> 69 </li> 70 <li> 71 <a href="#MIMETypeReference">Acuan Tipe MIME</a> 72 </li> 73</ol> 74 75 <!-- Key Classes --> 76<h2>Kelas-kelas utama</h2> 77 <ol> 78 <li> 79 {@link android.content.ContentProvider} 80 </li> 81 <li> 82 {@link android.content.ContentResolver} 83 </li> 84 <li> 85 {@link android.database.Cursor} 86 </li> 87 <li> 88 {@link android.net.Uri} 89 </li> 90 </ol> 91 92 <!-- Related Samples --> 93<h2>Contoh-Contoh Terkait</h2> 94 <ol> 95 <li> 96 <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html"> 97 Kursor (Orang)</a> 98 </li> 99 <li> 100 <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html"> 101 Kursor (Telepon)</a> 102 </li> 103 </ol> 104 105 <!-- See also --> 106<h2>Lihat juga</h2> 107 <ol> 108 <li> 109 <a href="{@docRoot}guide/topics/providers/content-provider-creating.html"> 110 Membuat Penyedia Konten</a> 111 </li> 112 <li> 113 <a href="{@docRoot}guide/topics/providers/calendar-provider.html"> 114 Penyedia Kalender</a> 115 </li> 116 </ol> 117</div> 118</div> 119 120 <!-- Intro paragraphs --> 121<p> 122 Penyedia konten mengelola akses ke repository data pusat. Penyedia 123 adalah bagian dari aplikasi Android, yang sering menyediakan UI-nya sendiri untuk menggunakan 124 data. Akan tetapi, penyedia konten terutama dimaksudkan untuk digunakan oleh 125 aplikasi lain, yang mengakses penyedia itu melalui objek klien penyedia. Bersama-sama, penyedia 126 dan klien penyedia menawarkan antarmuka standar yang konsisten ke data yang juga menangani 127 komunikasi antar-proses dan akses data aman. 128</p> 129<p> 130 Topik ini menerangkan dasar-dasar dari hal-hal berikut: 131</p> 132 <ul> 133 <li>Cara kerja penyedia konten.</li> 134 <li>API yang Anda gunakan untuk mengambil data dari penyedia konten.</li> 135 <li>API yang Anda gunakan untuk menyisipkan, memperbarui, atau menghapus data dalam penyedia konten.</li> 136 <li>Fitur API lainnya yang memudahkan kita menggunakan penyedia.</li> 137 </ul> 138 139 <!-- Basics --> 140<h2 id="Basics">Ikhtisar</h2> 141<p> 142 Penyedia konten menyajikan data ke aplikasi eksternal sebagai satu atau beberapa tabel yang 143 serupa dengan tabel-tabel yang ditemukan dalam database relasional. Sebuah baris mewakili instance beberapa tipe 144 data yang dikumpulkan penyedia, dan tiap kolom dalam baris mewakili sepotong 145 data yang dikumpulkan untuk sebuah instance. 146</p> 147<p> 148 Misalnya, salah satu penyedia bawaan di platform Android adalah kamus pengguna, yang 149 menyimpan ejaan kata-kata tidak-standar yang ingin disimpan pengguna. Tabel 1 mengilustrasikan 150 wujud data yang mungkin ada dalam tabel penyedia ini: 151</p> 152<p class="table-caption"> 153 <strong>Tabel 1:</strong> Contoh tabel kamus pengguna. 154</p> 155<table id="table1" style="width: 50%;"> 156 <tr> 157 <th style="width:20%" align="center" scope="col">word</th> 158 <th style="width:20%" align="center" scope="col">app id</th> 159 <th style="width:20%" align="center" scope="col">frequency</th> 160 <th style="width:20%" align="center" scope="col">locale</th> 161 <th style="width:20%" align="center" scope="col">_ID</th> 162 </tr> 163 <tr> 164 <td align="center" scope="row">mapreduce</td> 165 <td align="center">user1</td> 166 <td align="center">100</td> 167 <td align="center">en_US</td> 168 <td align="center">1</td> 169 </tr> 170 <tr> 171 <td align="center" scope="row">precompiler</td> 172 <td align="center">user14</td> 173 <td align="center">200</td> 174 <td align="center">fr_FR</td> 175 <td align="center">2</td> 176 </tr> 177 <tr> 178 <td align="center" scope="row">applet</td> 179 <td align="center">user2</td> 180 <td align="center">225</td> 181 <td align="center">fr_CA</td> 182 <td align="center">3</td> 183 </tr> 184 <tr> 185 <td align="center" scope="row">const</td> 186 <td align="center">user1</td> 187 <td align="center">255</td> 188 <td align="center">pt_BR</td> 189 <td align="center">4</td> 190 </tr> 191 <tr> 192 <td align="center" scope="row">int</td> 193 <td align="center">user5</td> 194 <td align="center">100</td> 195 <td align="center">en_UK</td> 196 <td align="center">5</td> 197 </tr> 198</table> 199<p> 200 Dalam tabel 1, tiap baris mewakili instance sebuah kata yang mungkin tidak 201 ditemukan dalam kamus standar. Tiap kolom mewakili beberapa data untuk kata itu, misalnya 202 bahasa lokal tempat kata itu ditemukan kali pertama. Header kolom adalah nama kolom yang disimpan dalam 203 penyedia. Untuk mengacu ke bahasa lokal suatu baris, Anda mengacu ke kolom <code>locale</code>-nya. Untuk 204 penyedia ini, kolom <code>_ID</code> berfungsi sebagai "kunci utama" kolom yang 205 dipelihara oleh penyedia secara otomatis. 206</p> 207<p class="note"> 208 <strong>Catatan:</strong> Penyedia tidak diharuskan memiliki kunci utama, dan tidak diharuskan 209 menggunakan <code>_ID</code> sebagai nama kolom kunci utama jika kunci itu ada. Akan tetapi, 210 jika Anda ingin mengikat data dari penyedia ke {@link android.widget.ListView}, salah satu 211 nama kolom harus <code>_ID</code>. Ketentuan ini dijelaskan secara lebih detail di bagian 212 <a href="#DisplayResults">Menampilkan hasil query</a>. 213</p> 214<h3 id="ClientProvider">Mengakses penyedia</h3> 215<p> 216 Aplikasi mengakses data dari penyedia konten dengan 217 sebuah objek klien {@link android.content.ContentResolver}. Objek ini memiliki metode yang memanggil 218 metode dengan nama identik dalam objek penyedia, instance salah satu 219 subkelas konkret dari {@link android.content.ContentProvider}. Metode-metode 220 {@link android.content.ContentResolver} menyediakan fungsi-fungsi dasar 221 "CRUD" (create, retrieve, update, dan delete) pada penyimpanan yang persisten. 222</p> 223<p> 224 Objek {@link android.content.ContentResolver} dalam 225 proses aplikasi klien dan objek {@link android.content.ContentProvider} dalam aplikasi yang memiliki 226 penyedia itu secara otomatis akan menangani komunikasi antar-proses. 227 {@link android.content.ContentProvider} juga berfungsi sebagai lapisan abstraksi antara 228 repository datanya dan penampilan eksternal data sebagai tabel. 229</p> 230<p class="note"> 231 <strong>Catatan:</strong> Untuk mengakses penyedia, aplikasi Anda biasanya harus meminta 232 izin tertentu dalam file manifesnya. Hal ini dijelaskan lebih detail di bagian 233 <a href="#Permissions">Izin Penyedia Konten</a> 234</p> 235<p> 236 Misalnya, untuk mendapatkan daftar kata dan lokalnya dari Penyedia Kamus Pengguna, 237 Anda memanggil {@link android.content.ContentResolver#query ContentResolver.query()}. 238 Metode {@link android.content.ContentResolver#query query()} memanggil 239 metode {@link android.content.ContentProvider#query ContentProvider.query()} yang didefinisikan oleh 240 Penyedia Kamus Pengguna. Baris-baris kode berikut menunjukkan sebuah 241 panggilan {@link android.content.ContentResolver#query ContentResolver.query()}: 242<p> 243<pre> 244// Queries the user dictionary and returns results 245mCursor = getContentResolver().query( 246 UserDictionary.Words.CONTENT_URI, // The content URI of the words table 247 mProjection, // The columns to return for each row 248 mSelectionClause // Selection criteria 249 mSelectionArgs, // Selection criteria 250 mSortOrder); // The sort order for the returned rows 251</pre> 252<p> 253 Tabel 2 menampilkan cara argumen untuk 254 {@link android.content.ContentResolver#query 255 query(Uri,projection,selection,selectionArgs,sortOrder)} cocok dengan sebuah pernyataan SELECT di SQL: 256</p> 257<p class="table-caption"> 258 <strong>Tabel 2:</strong> Query() dibandingkan dengan query SQL. 259</p> 260<table id="table2" style="width: 75%;"> 261 <tr> 262 <th style="width:25%" align="center" scope="col">Argumen query()</th> 263 <th style="width:25%" align="center" scope="col">Kata kunci/parameter SELECT</th> 264 <th style="width:50%" align="center" scope="col">Catatan</th> 265 </tr> 266 <tr> 267 <td align="center"><code>Uri</code></td> 268 <td align="center"><code>FROM <em>table_name</em></code></td> 269 <td><code>Uri</code> memetakan ke tabel dalam penyedia yang bernama <em>table_name</em>.</td> 270 </tr> 271 <tr> 272 <td align="center"><code>projection</code></td> 273 <td align="center"><code><em>col,col,col,...</em></code></td> 274 <td> 275 <code>projection</code> adalah satu larik kolom yang harus disertakan untuk tiap baris 276 yang diambil. 277 </td> 278 </tr> 279 <tr> 280 <td align="center"><code>selection</code></td> 281 <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td> 282 <td><code>selection</code> menetapkan kriteria untuk memilih baris.</td> 283 </tr> 284 <tr> 285 <td align="center"><code>selectionArgs</code></td> 286 <td align="center"> 287 (Tidak ada padanan persis. Argumen pemilihan mengganti <code>?</code> placeholder dalam 288 klausa pemilihan.) 289 </td> 290 </tr> 291 <tr> 292 <td align="center"><code>sortOrder</code></td> 293 <td align="center"><code>ORDER BY <em>col,col,...</em></code></td> 294 <td> 295 <code>sortOrder</code> menetapkan urutan munculnya baris dalam 296 {@link android.database.Cursor} yang dihasilkan. 297 </td> 298 </tr> 299</table> 300<h3 id="ContentURIs">URI Konten</h3> 301<p> 302 <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten 303 menyertakan nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah 304 nama yang menunjuk ke tabel (<strong>path</strong>). Bila Anda memanggil 305 metode klien untuk mengakses tabel dalam penyedia, URI konten untuk tabel itu adalah salah satu 306 argumennya. 307</p> 308<p> 309 Dalam baris kode sebelumnya, konstanta 310 {@link android.provider.UserDictionary.Words#CONTENT_URI} mengandung URI konten dari 311 tabel "words" kamus pengguna. Objek {@link android.content.ContentResolver} 312 akan mengurai otoritas URI, dan menggunakannya untuk "mengetahui" penyedia dengan 313 membandingkan otoritas tersebut dengan sebuah tabel sistem berisi penyedia yang dikenal. 314{@link android.content.ContentResolver} kemudian bisa mengirim argumen query ke penyedia 315 yang benar. 316</p> 317<p> 318 {@link android.content.ContentProvider} menggunakan bagian path dari URI konten untuk memilih 319 tabel yang akan diakses. Penyedia biasanya memiliki <strong>path</strong> untuk tiap tabel yang dieksposnya. 320</p> 321<p> 322 Dalam baris kode sebelumnya, URI lengkap untuk tabel "words" adalah: 323</p> 324<pre> 325content://user_dictionary/words 326</pre> 327<p> 328 dalam hal ini string <code>user_dictionary</code> adalah otoritas penyedia, dan string 329 <code>words</code> adalah path tabel. String 330 <code>content://</code> (<strong>skema</strong>) selalu ada, 331 dan mengidentifikasinya sebagai URI konten. 332</p> 333<p> 334 Banyak penyedia yang memperbolehkan Anda mengakses satu baris dalam tabel dengan menambahkan sebuah ID nilai 335 ke akhir URI. Misalnya, untuk mengambil sebuah baris yang <code>_ID</code>-nya adalah 336 <code>4</code> dari kamus pengguna, Anda bisa menggunakan URI konten ini: 337</p> 338<pre> 339Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4); 340</pre> 341<p> 342 Anda akan sering menggunakan nilai-nilai ID bila telah mengambil satu set baris kemudian ingin memperbarui atau menghapus 343 salah satunya. 344</p> 345<p class="note"> 346 <strong>Catatan:</strong> Kelas-kelas {@link android.net.Uri} dan {@link android.net.Uri.Builder} 347 berisi metode praktis untuk membangun objek dari string URI yang tersusun dengan baik. 348{@link android.content.ContentUris} berisi metode praktis untuk menambahkan nilai ID ke 349 URI. Cuplikan kode sebelumnya menggunakan {@link android.content.ContentUris#withAppendedId 350 withAppendedId()} untuk menambahkan id ke URI konten User Dictionary. 351</p> 352 353 354 <!-- Retrieving Data from the Provider --> 355<h2 id="SimpleQuery">Mengambil Data dari Penyedia</h2> 356<p> 357 Bagian ini menerangkan cara mengambil data dari penyedia, dengan menggunakan Penyedia Kamus Pengguna 358 sebagai contoh. 359</p> 360<p class="note"> 361 Demi kejelasan, cuplikan kode di bagian ini memanggil 362 {@link android.content.ContentResolver#query ContentResolver.query()} pada "UI thread"". Akan tetapi, dalam 363 kode sesungguhnya, Anda harus melakukan query secara asinkron pada sebuah thread terpisah. Satu cara melakukannya 364 adalah menggunakan kelas {@link android.content.CursorLoader}, yang dijelaskan 365 lebih detail dalam panduan <a href="{@docRoot}guide/components/loaders.html"> 366 Loader</a>. Juga, baris-baris kode tersebut hanyalah cuplikan; tidak menunjukkan sebuah aplikasi 367 lengkap. 368</p> 369<p> 370 Untuk mengambil data dari penyedia, ikutilah langkah-langkah dasar ini: 371</p> 372<ol> 373 <li> 374 Minta izin akses baca untuk penyedia itu. 375 </li> 376 <li> 377 Definisikan kode yang mengirim query ke penyedia. 378 </li> 379</ol> 380<h3 id="RequestPermissions">Meminta izin akses baca</h3> 381<p> 382 Untuk mengambil data dari penyedia, aplikasi Anda memerlukan "izin akses baca" untuk 383 penyedia itu. Anda tidak bisa meminta izin ini saat runtime; sebagai gantinya, Anda harus menetapkan bahwa 384 Anda memerlukan izin ini dalam manifes, dengan menggunakan elemen 385<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> 386 dan nama persis izin yang didefinisikan oleh 387 penyedia itu. Bila menetapkan elemen ini dalam manifes, Anda secara efektif "meminta" 388 izin ini untuk aplikasi Anda. Bila pengguna menginstal aplikasi Anda, mereka secara implisit akan memberikan 389 permintaan ini. 390</p> 391<p> 392 Untuk menemukan nama persis dari izin akses baca untuk penyedia yang sedang Anda gunakan, serta 393 nama-nama izin akses lain yang digunakan oleh penyedia, lihatlah dalam 394 dokumentasi penyedia. 395</p> 396<p> 397 Peran izin dalam yang mengakses penyedia dijelaskan lebih detail di bagian 398 <a href="#Permissions">Izin Penyedia Konten</a>. 399</p> 400<p> 401 Penyedia Kamus Pengguna mendefinisikan izin 402 <code>android.permission.READ_USER_DICTIONARY</code> dalam file manifesnya, sehingga 403 aplikasi yang ingin membaca dari penyedia itu harus meminta izin ini. 404</p> 405<!-- Constructing the query --> 406<h3 id="Query">Membuat query</h3> 407<p> 408 Langkah berikutnya dalam mengambil data penyedia adalah membuat query. Cuplikan kode pertama ini 409 mendefinisikan beberapa variabel untuk mengakses Penyedia Kamus Pengguna: 410</p> 411<pre class="prettyprint"> 412 413// A "projection" defines the columns that will be returned for each row 414String[] mProjection = 415{ 416 UserDictionary.Words._ID, // Contract class constant for the _ID column name 417 UserDictionary.Words.WORD, // Contract class constant for the word column name 418 UserDictionary.Words.LOCALE // Contract class constant for the locale column name 419}; 420 421// Defines a string to contain the selection clause 422String mSelectionClause = null; 423 424// Initializes an array to contain selection arguments 425String[] mSelectionArgs = {""}; 426 427</pre> 428<p> 429 Cuplikan berikutnya menampilkan cara menggunakan 430 {@link android.content.ContentResolver#query ContentResolver.query()}, dengan menggunakan Penyedia Kamus Pengguna 431 sebagai contoh. Query klien penyedia serupa dengan query SQL, dan berisi satu 432 set kolom yang akan dihasilkan, satu set kriteria pemilihan, dan urutan sortir. 433</p> 434<p> 435 Set kolom yang harus dikembalikan query disebut dengan <strong>proyeksi</strong> 436 (variabel <code>mProjection</code>). 437</p> 438<p> 439 Ekspresi yang menetapkan baris yang harus diambil dipecah menjadi klausa pemilihan dan 440 argumen pemilihan. Klausa pemilihan adalah kombinasi ekspresi logis dan boolean, 441 nama kolom, dan nilai (variabel <code>mSelectionClause</code>). Jika Anda menetapkan 442 parameter <code>?</code> yang bisa diganti, sebagai ganti nilai, metode query akan mengambil nilai 443 dari larik argumen pemilihan (variabel <code>mSelectionArgs</code>). 444</p> 445<p> 446 Dalam cuplikan berikutnya, jika pengguna tidak memasukkan sebuah kata, klausa pemilihan akan diatur ke 447 <code>null</code>, dan query menghasilkan semua kata dalam penyedia. Jika pengguna memasukkan 448 sebuah kata, klausa pemilihan akan diatur ke <code>UserDictionary.Words.WORD + " = ?"</code> dan 449 elemen pertama larik argumen pemilihan diatur ke kata yang dimasukkan pengguna. 450</p> 451<pre class="prettyprint"> 452/* 453 * This defines a one-element String array to contain the selection argument. 454 */ 455String[] mSelectionArgs = {""}; 456 457// Gets a word from the UI 458mSearchString = mSearchWord.getText().toString(); 459 460// Remember to insert code here to check for invalid or malicious input. 461 462// If the word is the empty string, gets everything 463if (TextUtils.isEmpty(mSearchString)) { 464 // Setting the selection clause to null will return all words 465 mSelectionClause = null; 466 mSelectionArgs[0] = ""; 467 468} else { 469 // Constructs a selection clause that matches the word that the user entered. 470 mSelectionClause = UserDictionary.Words.WORD + " = ?"; 471 472 // Moves the user's input string to the selection arguments. 473 mSelectionArgs[0] = mSearchString; 474 475} 476 477// Does a query against the table and returns a Cursor object 478mCursor = getContentResolver().query( 479 UserDictionary.Words.CONTENT_URI, // The content URI of the words table 480 mProjection, // The columns to return for each row 481 mSelectionClause // Either null, or the word the user entered 482 mSelectionArgs, // Either empty, or the string the user entered 483 mSortOrder); // The sort order for the returned rows 484 485// Some providers return null if an error occurs, others throw an exception 486if (null == mCursor) { 487 /* 488 * Insert code here to handle the error. Be sure not to use the cursor! You may want to 489 * call android.util.Log.e() to log this error. 490 * 491 */ 492// If the Cursor is empty, the provider found no matches 493} else if (mCursor.getCount() < 1) { 494 495 /* 496 * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily 497 * an error. You may want to offer the user the option to insert a new row, or re-type the 498 * search term. 499 */ 500 501} else { 502 // Insert code here to do something with the results 503 504} 505</pre> 506<p> 507 Query ini analog dengan pernyataan SQL: 508</p> 509<pre> 510SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC; 511</pre> 512<p> 513 Dalam pernyataan SQL ini, nama kolom yang sesungguhnya digunakan sebagai ganti konstanta kelas kontrak. 514</p> 515<h4 id="Injection">Melindungi dari input merusak</h4> 516<p> 517 Jika data dikelola oleh penyedia konten berada dalam database SQL, memasukkan data tak dipercaya eksternal 518 ke dalam pernyataan SQL mentah bisa menyebabkan injeksi SQL. 519</p> 520<p> 521 Perhatikan klausa pemilihan ini: 522</p> 523<pre> 524// Constructs a selection clause by concatenating the user's input to the column name 525String mSelectionClause = "var = " + mUserInput; 526</pre> 527<p> 528 Jika melakukannya, Anda akan membuat pengguna menyambungkan SQL merusak ke pernyataan SQL Anda. 529 Misalnya, pengguna bisa memasukkan "nothing; DROP TABLE *;" untuk <code>mUserInput</code>, yang 530 akan menghasilkan klausa pemilihan <code>var = nothing; DROP TABLE *;</code>. Karena 531 klausa pemilihan diperlakukan sebagai pernyataan SQL, hal ini bisa menyebabkan penyedia itu menghapus semua 532 tabel dalam database SQLite yang mendasarinya (kecuali penyedia disiapkan untuk menangkap upaya 533 <a href="http://en.wikipedia.org/wiki/SQL_injection">injeksi SQL</a>). 534</p> 535<p> 536 Untuk menghindari masalah ini, gunakan klausa pemilihan yang menggunakan <code>?</code> sebagai 537 parameter yang bisa diganti dan larik argumen pemilihan yang terpisah. Bila Anda melakukannya, input pengguna 538 akan dibatasi secara langsung pada query agar tidak ditafsirkan sebagai bagian dari pernyataan SQL. 539 Karena tidak diperlakukan sebagai SQL, input pengguna tidak bisa menyuntikkan SQL merusak. Sebagai ganti menggunakan 540 penyambungan untuk menyertakan input pengguna, gunakan klausa pemilihan ini: 541</p> 542<pre> 543// Constructs a selection clause with a replaceable parameter 544String mSelectionClause = "var = ?"; 545</pre> 546<p> 547 Buat larik argumen pemilihan seperti ini: 548</p> 549<pre> 550// Defines an array to contain the selection arguments 551String[] selectionArgs = {""}; 552</pre> 553<p> 554 Masukkan nilai dalam larik argumen pemilihan seperti ini: 555</p> 556<pre> 557// Sets the selection argument to the user's input 558selectionArgs[0] = mUserInput; 559</pre> 560<p> 561 Sebuah klausa pemilihan yang menggunakan <code>?</code> sebagai parameter yang bisa diganti dan sebuah larik 562 argumen pemilihan adalah cara yang lebih disukai untuk menyebutkan pemilihan, sekalipun penyedia tidak 563 dibuat berdasarkan database SQL. 564</p> 565<!-- Displaying the results --> 566<h3 id="DisplayResults">Menampilkan hasil query</h3> 567<p> 568 Metode klien {@link android.content.ContentResolver#query ContentResolver.query()} selalu 569 menghasilkan {@link android.database.Cursor} berisi kolom-kolom yang ditetapkan oleh 570 proyeksi query untuk baris yang cocok dengan kriteria pemilihan query. Objek 571 {@link android.database.Cursor} menyediakan akses baca acak ke baris dan kolom yang 572 dimuatnya. Dengan metode {@link android.database.Cursor}, Anda bisa mengulang baris-baris dalam 573 hasil, menentukan tipe data tiap kolom, mengambil data dari kolom, dan memeriksa 574 properti lain dari hasil. Beberapa implementasi {@link android.database.Cursor} 575 akan memperbarui objek secara otomatis bila data penyedia berubah, atau memicu metode dalam objek pengamat 576 bila {@link android.database.Cursor} berubah, atau keduanya. 577</p> 578<p class="note"> 579 <strong>Catatan:</strong> Penyedia bisa membatasi akses ke kolom berdasarkan sifat 580 objek yang membuat query. Misalnya, Penyedia Kontak membatasi akses untuk beberapa kolom pada 581 adaptor sinkronisasi, sehingga tidak akan mengembalikannya ke aktivitas atau layanan. 582</p> 583<p> 584 Jika tidak ada baris yang cocok dengan kriteria pemilihan, penyedia 585 akan mengembalikan objek {@link android.database.Cursor} dengan 586 {@link android.database.Cursor#getCount Cursor.getCount()} adalah 0 (kursor kosong). 587</p> 588<p> 589 Jika terjadi kesalahan internal, hasil query akan bergantung pada penyedia tertentu. Penyedia bisa 590 memilih untuk menghasilkan <code>null</code>, atau melontarkan {@link java.lang.Exception}. 591</p> 592<p> 593 Karena {@link android.database.Cursor} adalah "daftar" baris, cara yang cocok untuk menampilkan 594 konten {@link android.database.Cursor} adalah mengaitkannya dengan {@link android.widget.ListView} 595 melalui {@link android.widget.SimpleCursorAdapter}. 596</p> 597<p> 598 Cuplikan berikut melanjutkan kode dari cuplikan sebelumnya. Cuplikan ini membuat 599 objek {@link android.widget.SimpleCursorAdapter} berisi {@link android.database.Cursor} 600 yang diambil oleh query, dan mengatur objek ini menjadi adaptor bagi 601 {@link android.widget.ListView}: 602</p> 603<pre class="prettyprint"> 604// Defines a list of columns to retrieve from the Cursor and load into an output row 605String[] mWordListColumns = 606{ 607 UserDictionary.Words.WORD, // Contract class constant containing the word column name 608 UserDictionary.Words.LOCALE // Contract class constant containing the locale column name 609}; 610 611// Defines a list of View IDs that will receive the Cursor columns for each row 612int[] mWordListItems = { R.id.dictWord, R.id.locale}; 613 614// Creates a new SimpleCursorAdapter 615mCursorAdapter = new SimpleCursorAdapter( 616 getApplicationContext(), // The application's Context object 617 R.layout.wordlistrow, // A layout in XML for one row in the ListView 618 mCursor, // The result from the query 619 mWordListColumns, // A string array of column names in the cursor 620 mWordListItems, // An integer array of view IDs in the row layout 621 0); // Flags (usually none are needed) 622 623// Sets the adapter for the ListView 624mWordList.setAdapter(mCursorAdapter); 625</pre> 626<p class="note"> 627 <strong>Catatan:</strong> Untuk mendukung {@link android.widget.ListView} dengan 628 {@link android.database.Cursor}, kursor harus berisi kolom bernama <code>_ID</code>. 629 Karena itu, query yang ditampilkan sebelumnya mengambil kolom <code>_ID</code> untuk 630 tabel "words", walaupun {@link android.widget.ListView} tidak menampilkannya. 631 Pembatasan ini juga menjelaskan mengapa sebagian besar penyedia memiliki kolom <code>_ID</code> untuk masing-masing 632 tabelnya. 633</p> 634 635 <!-- Getting data from query results --> 636<h3 id="GettingResults">Mendapatkan data dari hasil query</h3> 637<p> 638 Daripada sekadar menampilkan hasil query, Anda bisa menggunakannya untuk tugas-tugas lain. Misalnya, 639 Anda bisa mengambil ejaan dari kamus pengguna kemudian mencarinya dalam 640 penyedia lain. Caranya, ulangi baris-baris dalam {@link android.database.Cursor}: 641</p> 642<pre class="prettyprint"> 643 644// Determine the column index of the column named "word" 645int index = mCursor.getColumnIndex(UserDictionary.Words.WORD); 646 647/* 648 * Only executes if the cursor is valid. The User Dictionary Provider returns null if 649 * an internal error occurs. Other providers may throw an Exception instead of returning null. 650 */ 651 652if (mCursor != null) { 653 /* 654 * Moves to the next row in the cursor. Before the first movement in the cursor, the 655 * "row pointer" is -1, and if you try to retrieve data at that position you will get an 656 * exception. 657 */ 658 while (mCursor.moveToNext()) { 659 660 // Gets the value from the column. 661 newWord = mCursor.getString(index); 662 663 // Insert code here to process the retrieved word. 664 665 ... 666 667 // end of while loop 668 } 669} else { 670 671 // Insert code here to report an error if the cursor is null or the provider threw an exception. 672} 673</pre> 674<p> 675 Implementasi {@link android.database.Cursor} berisi beberapa metode "get" untuk 676 mengambil berbagai tipe data dari objek. Misalnya, cuplikan sebelumnya 677 menggunakan {@link android.database.Cursor#getString getString()}. Implementasi juga memiliki 678 metode {@link android.database.Cursor#getType getType()} yang menghasilkan nilai yang menunjukkan 679 tipe data kolom. 680</p> 681 682 683 <!-- Requesting permissions --> 684<h2 id="Permissions">Izin Penyedia Konten</h2> 685<p> 686 Aplikasi penyedia bisa menetapkan izin yang harus dimiliki aplikasi lain untuk 687 mengakses data penyedia. Izin ini akan memastikan bahwa pengguna mengetahui data 688 yang coba diakses oleh aplikasi. Berdasarkan ketentuan penyedia, aplikasi lain 689 meminta izin yang diperlukannya untuk mengakses penyedia. Pengguna akhir akan melihat 690 izin yang diminta saat menginstal aplikasi. 691</p> 692<p> 693 Jika aplikasi penyedia tidak menetapkan izin apa pun, maka aplikasi lain tidak memiliki 694 akses ke data penyedia. Akan tetapi, komponen-komponen dalam aplikasi penyedia selalu memiliki 695 akses penuh untuk baca dan tulis, izin apa pun yang ditetapkan. 696</p> 697<p> 698 Seperti disebutkan sebelumnya, Penyedia Kamus Pengguna mensyaratkan izin 699 <code>android.permission.READ_USER_DICTIONARY</code> untuk mengambil data darinya. 700 Penyedia memiliki izin <code>android.permission.WRITE_USER_DICTIONARY</code> 701 yang terpisah untuk menyisipkan, memperbarui, atau menghapus data. 702</p> 703<p> 704 Untuk mendapatkan izin yang diperlukan untuk mengakses penyedia, aplikasi memintanya dengan elemen 705<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> 706 dalam file manifesnya. Bila Android Package Manager memasang aplikasi, pengguna 707 harus menyetujui semua izin yang diminta aplikasi. Jika pengguna menyetujui semuanya, 708 Package Manager akan melanjutkan instalasi; jika pengguna tidak menyetujui, Package Manager 709 akan membatalkan instalasi. 710</p> 711<p> 712 Elemen 713<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> 714 berikut meminta akses baca ke Penyedia Kamus Pengguna: 715</p> 716<pre> 717 <uses-permission android:name="android.permission.READ_USER_DICTIONARY"> 718</pre> 719<p> 720 Dampak izin pada akses penyedia dijelaskan secara lebih detail dalam panduan 721 <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>. 722</p> 723 724 725<!-- Inserting, Updating, and Deleting Data --> 726<h2 id="Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</h2> 727<p> 728 Lewat cara yang sama dengan cara mengambil data dari penyedia, Anda juga menggunakan interaksi antara 729 klien penyedia dan {@link android.content.ContentProvider} penyedia untuk memodifikasi data. 730 Anda memanggil metode {@link android.content.ContentResolver} dengan argumen yang diteruskan ke 731 metode {@link android.content.ContentProvider} yang sesuai. Penyedia dan klien penyedia 732 menangani secara otomatis keamanan dan komunikasi antar-proses. 733</p> 734<h3 id="Inserting">Menyisipkan data</h3> 735<p> 736 Untuk menyisipkan data ke penyedia, Anda memanggil metode 737 {@link android.content.ContentResolver#insert ContentResolver.insert()}. 738 Metode ini menyisipkan sebuah baris baru ke penyedia itu dan menghasilkan URI konten untuk baris itu. 739 Cuplikan ini menampilkan cara menyisipkan sebuah kata baru ke Penyedia Kamus Pengguna: 740</p> 741<pre class="prettyprint"> 742// Defines a new Uri object that receives the result of the insertion 743Uri mNewUri; 744 745... 746 747// Defines an object to contain the new values to insert 748ContentValues mNewValues = new ContentValues(); 749 750/* 751 * Sets the values of each column and inserts the word. The arguments to the "put" 752 * method are "column name" and "value" 753 */ 754mNewValues.put(UserDictionary.Words.APP_ID, "example.user"); 755mNewValues.put(UserDictionary.Words.LOCALE, "en_US"); 756mNewValues.put(UserDictionary.Words.WORD, "insert"); 757mNewValues.put(UserDictionary.Words.FREQUENCY, "100"); 758 759mNewUri = getContentResolver().insert( 760 UserDictionary.Word.CONTENT_URI, // the user dictionary content URI 761 mNewValues // the values to insert 762); 763</pre> 764<p> 765 Data untuk baris baru masuk ke dalam satu objek {@link android.content.ContentValues}, yang 766 serupa bentuknya dengan kursor satu-baris. Kolom dalam objek ini tidak perlu memiliki 767 tipe data yang sama, dan jika Anda tidak ingin menetapkan nilai sama sekali, Anda bisa mengatur kolom 768 ke <code>null</code> dengan menggunakan {@link android.content.ContentValues#putNull ContentValues.putNull()}. 769</p> 770<p> 771 Cuplikan ini tidak menambahkan kolom <code>_ID</code>, karena kolom ini dipelihara 772 secara otomatis. Penyedia menetapkan sebuah nilai unik <code>_ID</code> ke setiap baris yang 773 ditambahkan. Penyedia biasanya menggunakan nilai ini sebagai kunci utama tabel. 774</p> 775<p> 776 URI konten yang dihasilkan dalam <code>newUri</code> akan mengidentifikasi baris yang baru ditambahkan, dengan 777 format berikut: 778</p> 779<pre> 780content://user_dictionary/words/<id_value> 781</pre> 782<p> 783 <code><id_value></code> adalah konten <code>_ID</code> untuk baris baru. 784 Kebanyakan penyedia bisa mendeteksi bentuk URI konten ini secara otomatis kemudian melakukan 785 operasi yang diminta pada baris tersebut. 786</p> 787<p> 788 Untuk mendapatkan nilai <code>_ID</code> dari {@link android.net.Uri} yang dihasilkan, panggil 789 {@link android.content.ContentUris#parseId ContentUris.parseId()}. 790</p> 791<h3 id="Updating">Memperbarui data</h3> 792<p> 793 Untuk memperbarui sebuah baris, gunakan objek {@link android.content.ContentValues} dengan 794 nilai-nilai yang diperbarui, persis seperti yang Anda lakukan pada penyisipan, dan kriteria pemilihan persis seperti yang Anda lakukan pada query. 795 Metode klien yang Anda gunakan adalah 796 {@link android.content.ContentResolver#update ContentResolver.update()}. Anda hanya perlu menambahkan 797 nilai-nilai ke objek {@link android.content.ContentValues} untuk kolom yang sedang Anda perbarui. Jika Anda 798 ingin membersihkan konten kolom, aturlah nilai ke <code>null</code>. 799</p> 800<p> 801 Cuplikan berikut mengubah semua baris yang kolom lokalnya memiliki bahasa "en" ke 802 lokal <code>null</code>. Nilai hasil adalah jumlah baris yang diperbarui: 803</p> 804<pre> 805// Defines an object to contain the updated values 806ContentValues mUpdateValues = new ContentValues(); 807 808// Defines selection criteria for the rows you want to update 809String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?"; 810String[] mSelectionArgs = {"en_%"}; 811 812// Defines a variable to contain the number of updated rows 813int mRowsUpdated = 0; 814 815... 816 817/* 818 * Sets the updated value and updates the selected words. 819 */ 820mUpdateValues.putNull(UserDictionary.Words.LOCALE); 821 822mRowsUpdated = getContentResolver().update( 823 UserDictionary.Words.CONTENT_URI, // the user dictionary content URI 824 mUpdateValues // the columns to update 825 mSelectionClause // the column to select on 826 mSelectionArgs // the value to compare to 827); 828</pre> 829<p> 830 Anda juga harus membersihkan input pengguna bila memanggil 831 {@link android.content.ContentResolver#update ContentResolver.update()}. Untuk mengetahui selengkapnya tentang 832 hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>. 833</p> 834<h3 id="Deleting">Menghapus data</h3> 835<p> 836 Menghapus baris serupa dengan mengambil baris data: Anda menetapkan kriteria pemilihan untuk baris 837 yang ingin Anda hapus dan metode klien akan menghasilkan jumlah baris yang dihapus. 838 Cuplikan berikut menghapus baris yang appid-nya sama dengan "user". Metode menghasilkan 839 jumlah baris yang dihapus. 840</p> 841<pre> 842 843// Defines selection criteria for the rows you want to delete 844String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?"; 845String[] mSelectionArgs = {"user"}; 846 847// Defines a variable to contain the number of rows deleted 848int mRowsDeleted = 0; 849 850... 851 852// Deletes the words that match the selection criteria 853mRowsDeleted = getContentResolver().delete( 854 UserDictionary.Words.CONTENT_URI, // the user dictionary content URI 855 mSelectionClause // the column to select on 856 mSelectionArgs // the value to compare to 857); 858</pre> 859<p> 860 Anda juga harus membersihkan input pengguna bila memanggil 861 {@link android.content.ContentResolver#delete ContentResolver.delete()}. Untuk mengetahui selengkapnya tentang 862 hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>. 863</p> 864<!-- Provider Data Types --> 865<h2 id="DataTypes">Tipe Data Penyedia</h2> 866<p> 867 Penyedia konten bisa menawarkan berbagai tipe data. Penyedia Kamus Pengguna hanya menawarkan 868 teks, namun penyedia juga bisa menawarkan format berikut: 869</p> 870 <ul> 871 <li> 872 integer 873 </li> 874 <li> 875 long integer (long) 876 </li> 877 <li> 878 floating point 879 </li> 880 <li> 881 long floating point (double) 882 </li> 883 </ul> 884<p> 885 Tipe data lain yang sering digunakan penyedia adalah Binary Large OBject (BLOB) yang diimplementasikan sebagai 886 larik byte 64 KB. Anda bisa melihat tipe data yang tersedia dengan memperhatikan metode "get" 887 kelas {@link android.database.Cursor}. 888</p> 889<p> 890 Tipe data tiap kolom dalam penyedia biasanya tercantum dalam dokumentasinya. 891 Tipe data untuk Penyedia Kamus Pengguna tercantum dalam dokumentasi acuan 892 untuk kelas kontraknya {@link android.provider.UserDictionary.Words} (kelas kontrak 893 dijelaskan di bagian <a href="#ContractClasses">Kelas-kelas Kontrak</a>). 894 Anda juga bisa menentukan tipe data dengan memanggil {@link android.database.Cursor#getType 895 Cursor.getType()}. 896</p> 897<p> 898 Penyedia juga memelihara informasi tipe data MIME untuk tiap URI konten yang didefinisikannya. Anda bisa 899 menggunakan informasi tipe MIME untuk mengetahui apakah aplikasi Anda bisa menangani data yang 900 disediakan penyedia, atau memilih tipe penanganan berdasarkan tipe MIME. Anda biasanya memerlukan 901 tipe MIME saat menggunakan penyedia yang berisi 902 struktur atau file data yang kompleks. Misalnya, tabel {@link android.provider.ContactsContract.Data} 903 dalam Penyedia Kontak menggunakan tipe MIME untuk memberi label tipe data kontak yang disimpan di tiap 904 baris. Untuk mendapatkan tipe MIME yang sesuai dengan URI konten, panggil 905 {@link android.content.ContentResolver#getType ContentResolver.getType()}. 906</p> 907<p> 908 Bagian <a href="#MIMETypeReference">Acuan Tipe MIME</a> menerangkan 909 sintaks tipe MIME baik yang standar maupun custom. 910</p> 911 912 913<!-- Alternative Forms of Provider Access --> 914<h2 id="AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</h2> 915<p> 916 Tiga bentuk alternatif akses penyedia adalah penting dalam pengembangan aplikasi: 917</p> 918<ul> 919 <li> 920 <a href="#Batch">Akses batch</a>: Anda bisa membuat sebuah batch panggilan akses dengan metode-metode dalam 921 kelas {@link android.content.ContentProviderOperation}, kemudian menerapkannya dengan 922 {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. 923 </li> 924 <li> 925 Query asinkron: Anda harus melakukan query dalam thread terpisah. Satu cara melakukannya adalah 926 menggunakan objek {@link android.content.CursorLoader}. Contoh-contoh dalam panduan 927 <a href="{@docRoot}guide/components/loaders.html">Loader</a> memperagakan 928 cara melakukannya. 929 </li> 930 <li> 931 <a href="#Intents">Akses data melalui intent</a>: Walaupun tidak bisa mengirim intent 932 ke penyedia secara langsung, Anda bisa mengirim intent ke aplikasi penyedia, yang 933 biasanya paling lengkap dibekali untuk memodifikasi data penyedia. 934 </li> 935</ul> 936<p> 937 Akses batch dan modifikasi melalui intent dijelaskan dalam bagian-bagian berikut. 938</p> 939<h3 id="Batch">Akses batch</h3> 940<p> 941 Akses batch ke penyedia berguna untuk menyisipkan baris dalam jumlah besar, atau menyisipkan 942 baris ke dalam beberapa tabel dalam panggilan metode yang sama, atau biasanya melakukan satu set 943 operasi lintas batas proses sebagai transaksi (operasi atomik). 944</p> 945<p> 946 Untuk mengakses penyedia dalam "mode batch", 947 buat satu larik objek {@link android.content.ContentProviderOperation}, kemudian 948 kirim larik itu ke penyedia konten dengan 949 {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. Anda meneruskan 950 <em>otoritas</em> penyedia konten ke metode ini, daripada URI konten tertentu. 951 Ini memungkinkan tiap objek {@link android.content.ContentProviderOperation} dalam larik untuk bekerja 952 terhadap tabel yang berbeda. Panggilan ke {@link android.content.ContentResolver#applyBatch 953 ContentResolver.applyBatch()} menghasilkan satu larik hasil. 954</p> 955<p> 956 Keterangan kelas kontrak {@link android.provider.ContactsContract.RawContacts} 957 menyertakan cuplikan kode yang memperagakan penyisipan batch. Contoh aplikasi 958 <a href="{@docRoot}resources/samples/ContactManager/index.html">Contacts Manager</a> 959 berisi contoh akses batch dalam file sumber <code>ContactAdder.java</code>-nya 960. 961</p> 962<div class="sidebox-wrapper"> 963<div class="sidebox"> 964<h2>Menampilkan data dengan aplikasi pembantu</h2> 965<p> 966 Jika aplikasi Anda <em>memang</em> memiliki izin akses, Anda masih mungkin perlu menggunakan 967 intent untuk menampilkan data dalam aplikasi lain. Misalnya, aplikasi Kalender menerima 968 intent {@link android.content.Intent#ACTION_VIEW}, yang menampilkan tanggal atau kejadian tertentu. 969 Hal ini memungkinkan Anda menampilkan informasi kalender tanpa harus membuat UI sendiri. 970 Untuk mengetahui selengkapnya tentang fitur ini, lihat panduan 971 <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Penyedia Kalender</a>. 972</p> 973<p> 974 Aplikasi yang Anda kirimi intent tidak harus aplikasi 975 yang terkait dengan penyedia. Misalnya, Anda bisa mengambil satu kontak dari 976 Penyedia Kontak, kemudian mengirim intent {@link android.content.Intent#ACTION_VIEW} 977 berisi URI konten untuk gambar kontak itu ke penampil gambar. 978</p> 979</div> 980</div> 981<h3 id="Intents">Akses data melalui intent</h3> 982<p> 983 Intent bisa menyediakan akses tidak langsung ke penyedia konten. Anda memperbolehkan pengguna mengakses 984 data dalam penyedia sekalipun aplikasi Anda tidak memiliki izin akses, baik dengan 985 mendapatkan intent yang dihasilkan aplikasi yang memiliki izin, atau dengan mengaktifkan 986 aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaan di dalamnya. 987</p> 988<h4>Mendapatkan akses dengan izin sementara</h4> 989<p> 990 Anda bisa mengakses data dalam penyedia konten, sekalipun tidak memiliki 991 izin akses yang sesuai, dengan mengirimkan intent ke aplikasi yang memang memiliki izin dan 992 menerima hasil berupa intent berisi izin "URI". 993 Inilah izin untuk URI konten tertentu yang berlaku hingga aktivitas yang menerima 994 izin selesai. Aplikasi yang memiliki izin tetap akan memberikan 995 izin sementara dengan mengatur flag dalam intent yang dihasilkan: 996</p> 997<ul> 998 <li> 999 <strong>Izin baca:</strong> 1000 {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} 1001 </li> 1002 <li> 1003 <strong>Izin tulis:</strong> 1004 {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} 1005 </li> 1006</ul> 1007<p class="note"> 1008 <strong>Catatan:</strong> Flag ini tidak memberikan akses baca atau tulis umum ke penyedia 1009 yang otoritasnya dimuat dalam URI konten. Aksesnya hanya untuk URI itu sendiri. 1010</p> 1011<p> 1012 Penyedia mendefinisikan izin URI untuk URI konten dalam manifesnya, dengan menggunakan atribut 1013<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code> 1014 dari elemen 1015<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> 1016, serta elemen anak 1017<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code> 1018 dari elemen 1019<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code>. 1020 Mekanisme izin URI dijelaskan secara lebih detail dalam panduan 1021 <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>, 1022 di bagian "Izin URI". 1023</p> 1024<p> 1025 Misalnya, Anda bisa mengambil data untuk satu kontak di Penyedia Kontak, sekalipun tidak 1026 memiliki izin {@link android.Manifest.permission#READ_CONTACTS}. Anda mungkin ingin melakukan 1027 ini dalam aplikasi yang mengirim kartu ucapan elektronik ke seorang kenalan pada hari ulang tahunnya. Sebagai ganti 1028 meminta {@link android.Manifest.permission#READ_CONTACTS}, yang memberi Anda akses ke semua 1029 kontak pengguna dan semua informasinya, Anda lebih baik membiarkan pengguna mengontrol 1030 kontak-kontak yang akan digunakan oleh aplikasi Anda. Caranya, gunakan proses berikut: 1031</p> 1032<ol> 1033 <li> 1034 Aplikasi Anda akan mengirim intent berisi tindakan 1035 {@link android.content.Intent#ACTION_PICK} dan tipe MIME "contacts" 1036 {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, dengan menggunakan 1037 metode {@link android.app.Activity#startActivityForResult 1038 startActivityForResult()}. 1039 </li> 1040 <li> 1041 Karena intent ini cocok dengan filter intent untuk 1042 aktivitas "pemilihan" aplikasi People, aktivitas akan muncul ke latar depan. 1043 </li> 1044 <li> 1045 Dalam aktivitas pemilihan, pengguna memilih sebuah 1046 kontak untuk diperbarui. Bila ini terjadi, aktivitas pemilihan akan memanggil 1047 {@link android.app.Activity#setResult setResult(resultcode, intent)} 1048 untuk membuat intent yang akan diberikan kembali ke aplikasi Anda. Intent itu berisi URI konten 1049 kontak yang dipilih pengguna, dan flag "extras" 1050 {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. Semua flag ini memberikan 1051 izin URI ke aplikasi Anda untuk membaca data kontak yang ditunjuk oleh 1052 URI konten. Aktivitas pemilihan kemudian memanggil {@link android.app.Activity#finish()} untuk 1053 mengembalikan kontrol ke aplikasi Anda. 1054 </li> 1055 <li> 1056 Aktivitas Anda akan kembali ke latar depan, dan sistem memanggil metode 1057 {@link android.app.Activity#onActivityResult onActivityResult()} 1058 aktivitas Anda. Metode ini menerima intent yang dihasilkan oleh aktivitas pemilihan dalam 1059 aplikasi People. 1060 </li> 1061 <li> 1062 Dengan URI konten dari intent yang dihasilkan, Anda bisa membaca data kontak 1063 dari Penyedia Kontak, sekalipun Anda tidak meminta izin akses baca tetap 1064 ke penyedia dalam manifes Anda. Anda kemudian bisa mendapatkan informasi hari ulang tahun si kontak 1065 atau alamat emailnya, kemudian mengirim kartu ucapan elektronik. 1066 </li> 1067</ol> 1068<h4>Menggunakan aplikasi lain</h4> 1069<p> 1070 Satu cara mudah agar pengguna bisa memodifikasi data yang izin aksesnya tidak Anda miliki adalah 1071 mengaktifkan aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaannya di sana. 1072</p> 1073<p> 1074 Misalnya, aplikasi Kalender menerima 1075 intent {@link android.content.Intent#ACTION_INSERT}, yang memungkinkan Anda mengaktifkan 1076 UI penyisipan aplikasi itu. Anda bisa meneruskan data "extras" dalam intent ini, yang 1077 digunakan aplikasi untuk mengisi dahulu UI-nya. Karena kejadian berulang memiliki sintaks yang rumit, 1078 cara yang lebih disukai untuk menyisipkan kejadian ke dalam Penyedia Kalender adalah mengaktifkan aplikasi Kalender dengan 1079 {@link android.content.Intent#ACTION_INSERT}, kemudian membiarkan pengguna menyisipkan kejadian di sana. 1080</p> 1081<!-- Contract Classes --> 1082<h2 id="ContractClasses">Kelas-kelas Kontrak</h2> 1083<p> 1084 Kelas kontrak mendefinisikan konstanta yang membantu aplikasi menggunakan URI konten, nama 1085 kolom, tindakan intent, dan fitur lain pada penyedia konten. Kelas kontrak tidak 1086 disertakan secara otomatis bersama penyedia; pengembang penyedia harus mendefinisikannya kemudian 1087 membuatnya tersedia bagi pengembang lain. Banyak penyedia yang disertakan pada platform Android 1088 memiliki kelas kontrak yang sesuai dalam {@link android.provider} paketnya. 1089</p> 1090<p> 1091 Misalnya, Penyedia Kamus Pengguna memiliki kelas kontrak 1092 {@link android.provider.UserDictionary} yang berisi URI konten dan konstanta nama kolom. URI 1093 konten untuk tabel "words" didefinisikan dalam konstanta 1094 {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}. 1095 Kelas {@link android.provider.UserDictionary.Words} juga berisi konstanta nama kolom, 1096 yang digunakan dalam cuplikan contoh pada panduan ini. Misalnya, sebuah proyeksi query bisa 1097 didefinisikan sebagai: 1098</p> 1099<pre> 1100String[] mProjection = 1101{ 1102 UserDictionary.Words._ID, 1103 UserDictionary.Words.WORD, 1104 UserDictionary.Words.LOCALE 1105}; 1106</pre> 1107<p> 1108 Kelas kontrak lain adalah {@link android.provider.ContactsContract} untuk Penyedia Kontak. 1109 Dokumentasi acuan untuk kelas ini menyertakan contoh cuplikan kode. Salah satu 1110 subkelasnya, {@link android.provider.ContactsContract.Intents.Insert}, adalah 1111 kelas kontrak yang berisi konstanta untuk intent dan data intent. 1112</p> 1113 1114 1115<!-- MIME Type Reference --> 1116<h2 id="MIMETypeReference">Acuan Tipe MIME</h2> 1117<p> 1118 Penyedia konten bisa menghasilkan tipe media MIME standar, atau string tipe MIME custom, atau keduanya. 1119</p> 1120<p> 1121 Tipe MIME memiliki format 1122</p> 1123<pre> 1124<em>type</em>/<em>subtype</em> 1125</pre> 1126<p> 1127 Misalnya, tipe MIME <code>text/html</code> yang dikenal luas memiliki tipe <code>text</code> dan 1128 subtipe <code>html</code>. Jika penyedia menghasilkan tipe ini untuk sebuah URI, artinya 1129 query dengan URI itu akan menghasilkan teks berisi tag HTML. 1130</p> 1131<p> 1132 String tipe MIME custom, yang juga disebut dengan tipe MIME "khusus vendor", memiliki nilai-nilai 1133 <em>tipe</em> dan <em>subtipe</em> yang lebih kompleks. Nilai <em>tipe</em> selalu 1134</p> 1135<pre> 1136vnd.android.cursor.<strong>dir</strong> 1137</pre> 1138<p> 1139 untuk beberapa baris, atau 1140</p> 1141<pre> 1142vnd.android.cursor.<strong>item</strong> 1143</pre> 1144<p> 1145 untuk satu baris. 1146</p> 1147<p> 1148 <em>Subtipe</em> adalah khusus penyedia. Penyedia bawaan Android biasanya memiliki subtipe 1149 sederhana. Misalnya, bila aplikasi Contacts membuat satu baris untuk nomor telepon, 1150 aplikasi akan mengatur tipe MIME berikut di baris itu: 1151</p> 1152<pre> 1153vnd.android.cursor.item/phone_v2 1154</pre> 1155<p> 1156 Perhatikan bahwa nilai subtipe adalah sekadar <code>phone_v2</code>. 1157</p> 1158<p> 1159 Pengembang penyedia lain bisa membuat pola subtipe sendiri berdasarkan 1160 otoritas dan nama-nama tabel penyedia. Misalnya, perhatikan penyedia yang berisi jadwal kereta api. 1161 Otoritas penyedia adalah <code>com.example.trains</code>, dan berisi tabel-tabel 1162 Line1, Line2, dan Line3. Untuk merespons URI konten 1163</p> 1164<p> 1165<pre> 1166content://com.example.trains/Line1 1167</pre> 1168<p> 1169 untuk tabel Line1, penyedia menghasilkan tipe MIME 1170</p> 1171<pre> 1172vnd.android.cursor.<strong>dir</strong>/vnd.example.line1 1173</pre> 1174<p> 1175 Untuk merespons URI konten 1176</p> 1177<pre> 1178content://com.example.trains/Line2/5 1179</pre> 1180<p> 1181 untuk baris 5 di tabel Line2, penyedia menghasilkan tipe MIME 1182</p> 1183<pre> 1184vnd.android.cursor.<strong>item</strong>/vnd.example.line2 1185</pre> 1186<p> 1187 Kebanyakan penyedia konten mendefinisikan konstanta kelas kontrak untuk tipe MIME yang digunakannya. Kelas kontrak 1188 {@link android.provider.ContactsContract.RawContacts} pada Penyedia Kontak 1189 misalnya, mendefinisikan konstanta 1190 {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} untuk tipe MIME 1191 baris kontak mentah tunggal. 1192</p> 1193<p> 1194 URI konten untuk baris-baris tunggal dijelaskan di bagian 1195 <a href="#ContentURIs">URI Konten</a>. 1196</p> 1197