1page.title=Membuat Penyedia Konten 2@jd:body 3<div id="qv-wrapper"> 4<div id="qv"> 5 6 7<h2>Dalam dokumen ini</h2> 8<ol> 9 <li> 10 <a href="#DataStorage">Mendesain Penyimpanan Data</a> 11 </li> 12 <li> 13 <a href="#ContentURI">Mendesain URI Konten</a> 14 </li> 15 <li> 16 <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a> 17 <ol> 18 <li> 19 <a href="#RequiredAccess">Metode-Metode yang Diperlukan</a> 20 </li> 21 <li> 22 <a href="#Query">Mengimplementasikan metode query()</a> 23 </li> 24 <li> 25 <a href="#Insert">Mengimplementasikan metode insert()</a> 26 </li> 27 <li> 28 <a href="#Delete">Mengimplementasikan metode delete()</a> 29 </li> 30 <li> 31 <a href="#Update">Mengimplementasikan metode update()</a> 32 </li> 33 <li> 34 <a href="#OnCreate">Mengimplementasikan metode onCreate()</a> 35 </li> 36 </ol> 37 </li> 38 <li> 39 <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a> 40 <ol> 41 <li> 42 <a href="#TableMIMETypes">Tipe MIME untuk tabel</a> 43 </li> 44 <li> 45 <a href="#FileMIMETypes">Tipe MIME untuk file</a> 46 </li> 47 </ol> 48 </li> 49 <li> 50 <a href="#ContractClass">Mengimplementasikan Kelas Kontrak</a> 51 </li> 52 <li> 53 <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a> 54 </li> 55 <li> 56 <a href="#ProviderElement">Elemen <provider></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.<appname></code>, Anda harus memberikan penyedia Anda 292 otoritas <code>com.example.<appname>.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.<appname>.provider/table1</code> dan 301 <code>com.example.<appname>.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://<authority>/<path></code> untuk tabel, dan 399 <code>content://<authority>/<path>/<id></code> untuk satu baris. 400</p> 401<p> 402 Metode {@link android.content.UriMatcher#addURI(String, String, int) addURI()} memetakan 403 otoritas dan path ke nilai integer. Metode {@link android.content.UriMatcher#match(Uri) 404 match()} menghasilkan nilai integer URI. Pernyataan <code>switch</code> 405 memilih antara melakukan query seluruh tabel dan melakukan query satu record: 406</p> 407<pre class="prettyprint"> 408public class ExampleProvider extends ContentProvider { 409... 410 // Creates a UriMatcher object. 411 private static final UriMatcher sUriMatcher; 412... 413 /* 414 * The calls to addURI() go here, for all of the content URI patterns that the provider 415 * should recognize. For this snippet, only the calls for table 3 are shown. 416 */ 417... 418 /* 419 * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used 420 * in the path 421 */ 422 sUriMatcher.addURI("com.example.app.provider", "table3", 1); 423 424 /* 425 * Sets the code for a single row to 2. In this case, the "#" wildcard is 426 * used. "content://com.example.app.provider/table3/3" matches, but 427 * "content://com.example.app.provider/table3 doesn't. 428 */ 429 sUriMatcher.addURI("com.example.app.provider", "table3/#", 2); 430... 431 // Implements ContentProvider.query() 432 public Cursor query( 433 Uri uri, 434 String[] projection, 435 String selection, 436 String[] selectionArgs, 437 String sortOrder) { 438... 439 /* 440 * Choose the table to query and a sort order based on the code returned for the incoming 441 * URI. Here, too, only the statements for table 3 are shown. 442 */ 443 switch (sUriMatcher.match(uri)) { 444 445 446 // If the incoming URI was for all of table3 447 case 1: 448 449 if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; 450 break; 451 452 // If the incoming URI was for a single row 453 case 2: 454 455 /* 456 * Because this URI was for a single row, the _ID value part is 457 * present. Get the last path segment from the URI; this is the _ID value. 458 * Then, append the value to the WHERE clause for the query 459 */ 460 selection = selection + "_ID = " uri.getLastPathSegment(); 461 break; 462 463 default: 464 ... 465 // If the URI is not recognized, you should do some error handling here. 466 } 467 // call the code to actually do the query 468 } 469</pre> 470<p> 471 Kelas lainnya, {@link android.content.ContentUris}, menyediakan metode praktis untuk menggunakan 472 bagian <code>id</code> URI konten. Kelas-kelas {@link android.net.Uri} dan 473 {@link android.net.Uri.Builder} menyertakan metode praktis untuk mengurai 474 objek {@link android.net.Uri} yang ada dan membuat objek baru. 475</p> 476 477<!-- Implementing the ContentProvider class --> 478<h2 id="ContentProvider">Mengimplementasikan Kelas ContentProvider</h2> 479<p> 480 Instance {@link android.content.ContentProvider} mengelola akses 481 ke satu set data terstruktur dengan menangani permintaan dari aplikasi lain. Semua bentuk 482 akses pada akhirnya akan memanggil {@link android.content.ContentResolver}, yang kemudian memanggil 483 metode konkret {@link android.content.ContentProvider} untuk mendapatkan akses. 484</p> 485<h3 id="RequiredAccess">Metode-metode yang diperlukan</h3> 486<p> 487 Kelas abstrak {@link android.content.ContentProvider} mendefinisikan enam metode abstrak yang 488 harus Anda implementasikan sebagai bagian dari subkelas konkret Anda sendiri. Semua metode ini kecuali 489 {@link android.content.ContentProvider#onCreate() onCreate()} dipanggil oleh aplikasi klien 490 yang berupaya mengakses penyedia konten Anda: 491</p> 492<dl> 493 <dt> 494 {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) 495 query()} 496 </dt> 497 <dd> 498 Mengambil data dari penyedia Anda. Menggunakan argumen untuk memilih tabel yang akan 499 di-query, baris dan kolom yang akan dihasilkan, dan urutan sortir hasilnya. 500 Menghasilkan data berupa objek {@link android.database.Cursor}. 501 </dd> 502 <dt> 503 {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} 504 </dt> 505 <dd> 506 Menyisipkan baris baru ke dalam penyedia Anda. Menggunakan argumen untuk memilih 507 tabel tujuan dan mendapatkan nilai-nilai kolom yang akan digunakan. Menghasilkan URI konten untuk 508 baris yang baru disisipkan. 509 </dd> 510 <dt> 511 {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) 512 update()} 513 </dt> 514 <dd> 515 Memperbarui baris yang ada di penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris 516 yang akan diperbarui dan mendapatkan nilai-nilai kolom yang diperbarui. Menghasilkan jumlah baris yang diperbarui. 517 </dd> 518 <dt> 519 {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} 520 </dt> 521 <dd> 522 Menghapus baris dari penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris yang akan 523 dihapus. Menghasilkan jumlah baris yang dihapus. 524 </dd> 525 <dt> 526 {@link android.content.ContentProvider#getType(Uri) getType()} 527 </dt> 528 <dd> 529 Menghasilkan tipe MIME yang sesuai dengan URI konten. Metode ini dijelaskan lebih detail 530 di bagian <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>. 531 </dd> 532 <dt> 533 {@link android.content.ContentProvider#onCreate() onCreate()} 534 </dt> 535 <dd> 536 Inisialisasi penyedia Anda. Sistem Android memanggil metode ini segera setelah 537 membuat penyedia Anda. Perhatikan bahwa penyedia Anda tidak dibuat hingga 538 objek {@link android.content.ContentResolver} mencoba mengaksesnya. 539 </dd> 540</dl> 541<p> 542 Perhatikan bahwa metode-metode ini memiliki signature yang sama dengan 543 metode-metode {@link android.content.ContentResolver} yang sama namanya. 544</p> 545<p> 546 Implementasi metode-metode ini harus memperhitungkan hal-hal berikut: 547</p> 548<ul> 549 <li> 550 Semua metode ini kecuali {@link android.content.ContentProvider#onCreate() onCreate()} 551 bisa dipanggil oleh beberapa thread sekaligus, jadi harus thread-safe (aman untuk thread). Untuk mengetahui 552 selengkapnya tentang multi-thread, lihat topik 553 <a href="{@docRoot}guide/components/processes-and-threads.html"> 554 Proses dan Thread</a>. 555 </li> 556 <li> 557 Hindari melakukan operasi yang lama dalam {@link android.content.ContentProvider#onCreate() 558 onCreate()}. Tunda inisialisasi tugas hingga benar-benar diperlukan. 559 Bagian <a href="#OnCreate">Mengimplementasikan metode onCreate()</a> 560 membahas hal ini secara lebih detail. 561 </li> 562 <li> 563 Walaupun harus mengimplementasikan metode-metode ini, kode Anda tidak harus melakukan apa pun selain 564 tipe data yang diharapkan. Misalnya, Anda mungkin ingin mencegah aplikasi lain 565 menyisipkan data ke dalam beberapa tabel. Caranya, Anda bisa mengabaikan panggilan ke 566 {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} dan menghasilkan 567 0. 568 </li> 569</ul> 570<h3 id="Query">Mengimplementasikan metode query()</h3> 571<p> 572 Metode 573 {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) 574 ContentProvider.query()} harus menghasilkan objek {@link android.database.Cursor}, atau jika 575 gagal, melontarkan {@link java.lang.Exception}. Jika menggunakan database SQLite sebagai 576 penyimpanan data, Anda bisa mengembalikan{@link android.database.Cursor} yang dikembalikan oleh salah satu metode 577 <code>query()</code> dari kelas {@link android.database.sqlite.SQLiteDatabase}. 578 Jika query tidak mencocokkan baris apa pun, Anda harus mengembalikan instance {@link android.database.Cursor} 579 yang metode {@link android.database.Cursor#getCount()}-nya mengembalikan 0. 580 Anda harus mengembalikan <code>null</code> hanya jika terjadi kesalahan internal selama proses query. 581</p> 582<p> 583 Jika Anda tidak menggunakan database SQLite sebagai penyimpanan data, gunakan salah satu subkelas konkret 584 {@link android.database.Cursor}. Misalnya, kelas {@link android.database.MatrixCursor} 585 mengimplementasikan kursor dengan masing-masing baris berupa larik {@link java.lang.Object}. Dengan kelas ini, 586 gunakan {@link android.database.MatrixCursor#addRow(Object[]) addRow()} untuk menambahkan baris baru. 587</p> 588<p> 589 Ingatlah bahwa sistem Android harus mampu mengomunikasikan {@link java.lang.Exception} 590 lintas batas proses. Android bisa melakukannya untuk eksepsi berikut yang mungkin berguna 591 dalam menangani kesalahan query: 592</p> 593<ul> 594 <li> 595 {@link java.lang.IllegalArgumentException} (Anda bisa saja melontarkannya jika penyedia Anda 596 menerima URI konten yang tidak sah) 597 </li> 598 <li> 599 {@link java.lang.NullPointerException} 600 </li> 601</ul> 602<h3 id="Insert">Mengimplementasikan metode insert()</h3> 603<p> 604 Metode {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} menambahkan satu 605 baris baru ke tabel yang sesuai, dengan menggunakan nilai-nilai dalam argumen {@link android.content.ContentValues}. 606 Jika kolom nama tidak ada dalam argumen {@link android.content.ContentValues}, Anda 607 mungkin perlu menyediakan nilai default untuknya, baik dalam kode penyedia atau dalam skema database 608 Anda. 609</p> 610<p> 611 Metode ini harus mengembalikan URI konten untuk baris baru. Untuk membuatnya, tambahkan nilai 612 <code>_ID</code> baris baru (atau kunci utama lainnya) ke tabel URI konten, dengan menggunakan 613 {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}. 614</p> 615<h3 id="Delete">Mengimplementasikan metode delete()</h3> 616<p> 617 Metode {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} 618 tidak harus menghapus baris-baris dari penyimpanan data Anda secara fisik. Jika menggunakan adaptor sinkronisasi 619 bersama penyedia, Anda harus mempertimbangkan penandaan baris yang dihapus 620 dengan flag "delete"; bukan menghilangkan baris itu sepenuhnya. Adaptor sinkronisasi bisa 621 memeriksa baris yang dihapus dan menghilangkannya dari server sebelum menghapusnya dari penyedia. 622</p> 623<h3 id="Update">Mengimplementasikan metode update()</h3> 624<p> 625 Metode {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) 626 update()} mengambil argumen {@link android.content.ContentValues} yang sama dengan yang digunakan oleh 627 {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, dan 628 argumen-argumen <code>selection</code> dan <code>selectionArgs</code> yang sama dengan yang digunakan oleh 629 {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} dan 630 {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) 631 ContentProvider.query()}. Hal ini bisa memungkinkan Anda menggunakan kembali kode di antara metode-metode ini. 632</p> 633<h3 id="OnCreate">Mengimplementasikan metode onCreate()</h3> 634<p> 635 Sistem Android memanggil {@link android.content.ContentProvider#onCreate() 636 onCreate()} saat memulai penyedia. Anda harus melakukan tugas-tugas inisialisasi yang berjalan cepat saja 637 dalam metode ini, serta menunda pembuatan database dan pemuatan data hingga penyedia benar-benar 638 menerima permintaan terhadap data. Jika Anda melakukan tugas yang memakan waktu dalam 639 {@link android.content.ContentProvider#onCreate() onCreate()}, Anda akan memperlambat 640 startup penyedia. Pada gilirannya, hal ini akan memperlambat respons dari penyedia terhadap 641 aplikasi lain. 642</p> 643<p> 644 Misalnya, jika menggunakan database SQLite, Anda bisa membuat 645 sebuah objek {@link android.database.sqlite.SQLiteOpenHelper} baru di 646 {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}, 647 kemudian membuat tabel-tabel SQL saat pertama kali membuka database itu. Untuk memperlancar hal ini, 648 saat pertama Anda memanggil {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase 649 getWritableDatabase()}, metode ini memanggil metode 650 {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) 651 SQLiteOpenHelper.onCreate()} secara otomatis. 652</p> 653<p> 654 Dua cuplikan berikut memperagakan interaksi antara 655 {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} dan 656 {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) 657 SQLiteOpenHelper.onCreate()}. Cuplikan pertama adalah implementasi 658 {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}: 659</p> 660<pre class="prettyprint"> 661public class ExampleProvider extends ContentProvider 662 663 /* 664 * Defines a handle to the database helper object. The MainDatabaseHelper class is defined 665 * in a following snippet. 666 */ 667 private MainDatabaseHelper mOpenHelper; 668 669 // Defines the database name 670 private static final String DBNAME = "mydb"; 671 672 // Holds the database object 673 private SQLiteDatabase db; 674 675 public boolean onCreate() { 676 677 /* 678 * Creates a new helper object. This method always returns quickly. 679 * Notice that the database itself isn't created or opened 680 * until SQLiteOpenHelper.getWritableDatabase is called 681 */ 682 mOpenHelper = new MainDatabaseHelper( 683 getContext(), // the application context 684 DBNAME, // the name of the database) 685 null, // uses the default SQLite cursor 686 1 // the version number 687 ); 688 689 return true; 690 } 691 692 ... 693 694 // Implements the provider's insert method 695 public Cursor insert(Uri uri, ContentValues values) { 696 // Insert code here to determine which table to open, handle error-checking, and so forth 697 698 ... 699 700 /* 701 * Gets a writeable database. This will trigger its creation if it doesn't already exist. 702 * 703 */ 704 db = mOpenHelper.getWritableDatabase(); 705 } 706} 707</pre> 708<p> 709 Cuplikan berikutnya adalah implementasi 710 {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) 711 SQLiteOpenHelper.onCreate()}, yang menyertakan kelas helper: 712</p> 713<pre class="prettyprint"> 714... 715// A string that defines the SQL statement for creating a table 716private static final String SQL_CREATE_MAIN = "CREATE TABLE " + 717 "main " + // Table's name 718 "(" + // The columns in the table 719 " _ID INTEGER PRIMARY KEY, " + 720 " WORD TEXT" 721 " FREQUENCY INTEGER " + 722 " LOCALE TEXT )"; 723... 724/** 725 * Helper class that actually creates and manages the provider's underlying data repository. 726 */ 727protected static final class MainDatabaseHelper extends SQLiteOpenHelper { 728 729 /* 730 * Instantiates an open helper for the provider's SQLite data repository 731 * Do not do database creation and upgrade here. 732 */ 733 MainDatabaseHelper(Context context) { 734 super(context, DBNAME, null, 1); 735 } 736 737 /* 738 * Creates the data repository. This is called when the provider attempts to open the 739 * repository and SQLite reports that it doesn't exist. 740 */ 741 public void onCreate(SQLiteDatabase db) { 742 743 // Creates the main table 744 db.execSQL(SQL_CREATE_MAIN); 745 } 746} 747</pre> 748 749 750<!-- Implementing ContentProvider MIME Types --> 751<h2 id="MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</h2> 752<p> 753 Kelas {@link android.content.ContentProvider} memiliki dua metode untuk menghasilkan tipe-tipe MIME: 754</p> 755<dl> 756 <dt> 757 {@link android.content.ContentProvider#getType(Uri) getType()} 758 </dt> 759 <dd> 760 Salah satu metode wajib yang harus Anda implementasikan untuk setiap penyedia. 761 </dd> 762 <dt> 763 {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} 764 </dt> 765 <dd> 766 Sebuah metode yang diharapkan untuk Anda implementasikan jika penyedia Anda menawarkan file. 767 </dd> 768</dl> 769<h3 id="TableMIMETypes">Tipe MIME untuk tabel</h3> 770<p> 771 Metode {@link android.content.ContentProvider#getType(Uri) getType()} mengembalikan 772 {@link java.lang.String} dengan format MIME yang menjelaskan tipe data yang dikembalikan oleh 773 argumen URI konten. Argumen {@link android.net.Uri} bisa berupa pola, bukannya URI tertentu; 774 dalam hal ini, Anda harus mengembalikan tipe data terkait URI konten yang cocok dengan 775 polanya. 776</p> 777<p> 778 Untuk tipe data umum misalnya teks, HTML, atau JPEG, 779 {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan 780 tipe MIME standar untuk data itu. Daftar lengkap tipe standar ini tersedia di situs web 781 <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a>. 782 783</p> 784<p> 785 Untuk URI konten yang menunjuk ke baris atau baris-baris data tabel, 786 {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan 787 tipe MIME dalam format MIME khusus vendor Android: 788</p> 789<ul> 790 <li> 791 Bagian tipe: <code>vnd</code> 792 </li> 793 <li> 794 Bagian subtipe: 795 <ul> 796 <li> 797 Jika pola URI adalah untuk satu baris: <code>android.cursor.<strong>item</strong>/</code> 798 </li> 799 <li> 800 Jika pola URI adalah untuk lebih dari satu baris: <code>android.cursor.<strong>dir</strong>/</code> 801 </li> 802 </ul> 803 </li> 804 <li> 805 Bagian khusus penyedia: <code>vnd.<name></code>.<code><type></code> 806 <p> 807 Anda menyediakan <code><name></code> dan <code><type></code>. 808 Nilai <code><name></code> harus unik secara global, 809 dan nilai <code><type></code> harus unik bagi pola URI 810 yang sesuai. Pilihan tepat untuk <code><name></code> adalah nama perusahaan Anda atau 811 sebagian dari nama paket Android aplikasi Anda. Pilihan tepat untuk 812 <code><type></code> adalah string yang mengidentifikasi tabel yang terkait dengan 813 URI. 814 </p> 815 816 </li> 817</ul> 818<p> 819 Misalnya, jika otoritas penyedia adalah 820 <code>com.example.app.provider</code>, dan penyedia mengekspos tabel bernama 821 <code>table1</code>, tipe MIME untuk beberapa baris dalam <code>table1</code> adalah: 822</p> 823<pre> 824vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1 825</pre> 826<p> 827 Untuk satu baris <code>table1</code>, tipe MIME adalah: 828</p> 829<pre> 830vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1 831</pre> 832<h3 id="FileMIMETypes">Tipe MIME untuk file</h3> 833<p> 834 Jika penyedia Anda menawarkan file, implementasikan 835 {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}. 836 Metode ini menghasilkan larik {@link java.lang.String} tipe MIME untuk file 837 yang bisa dikembalikan penyedia Anda untuk URI konten bersangkutan. Anda harus memfilter tipe MIME yang Anda tawarkan dengan argumen filter 838 tipe MIME, sehingga Anda hanya mengembalikan tipe MIME yang ingin ditangani klien. 839</p> 840<p> 841 Misalnya, perhatikan penyedia yang menawarkan gambar foto sebagai file dalam format <code>.jpg</code>, 842 <code>.png</code>, dan <code>.gif</code>. 843 Jika aplikasi memanggil {@link android.content.ContentResolver#getStreamTypes(Uri, String) 844 ContentResolver.getStreamTypes()} dengan string filter <code>image/*</code> (sesuatu yang 845 merupakan "gambar"), 846 maka metode {@link android.content.ContentProvider#getStreamTypes(Uri, String) 847 ContentProvider.getStreamTypes()} harus mengembalikan larik: 848</p> 849<pre> 850{ "image/jpeg", "image/png", "image/gif"} 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{"image/jpeg"} 860</pre> 861<p> 862 Jika penyedia Anda tidak menawarkan tipe MIME apa pun yang diminta dalam string filter, 863 {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} 864 harus mengembalikan <code>null</code>. 865</p> 866 867 868<!-- Implementing a Contract Class --> 869<h2 id="ContractClass">Mengimplementasikan Kelas Kontrak</h2> 870<p> 871 Kelas kontrak adalah kelas <code>public final</code> yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan 872metadata lain yang melekat ke penyedia. Kelas 873 membentuk sebuah kontrak antara penyedia dan aplikasi lain dengan memastikan bahwa penyedia 874 bisa diakses dengan benar sekalipun ada perubahan pada nilai URI sesungguhnya, nama kolom, 875 dan seterusnya. 876</p> 877<p> 878 Kelas kontrak juga membantu pengembang karena kelas ini biasanya memiliki nama-nama simbolik untuk konstantanya, 879 sehingga memperkecil kemungkinan pengembang menggunakan nilai yang salah untuk nama kolom atau URI. Karena berupa 880 kelas, kelas ini bisa berisi dokumentasi Javadoc. Lingkungan pengembangan terpadu (IDE) seperti 881 Eclipse secara otomatis bisa melengkapi nama-nama konstanta dari kelas kontrak dan menampilkan Javadoc untuk 882 konstanta. 883</p> 884<p> 885 Pengembang tidak bisa mengakses file kelas milik kelas kontrak dari aplikasi Anda, namun bisa 886 mengompilasinya secara statis ke dalam aplikasi mereka dari file <code>.jar</code> yang Anda sediakan. 887</p> 888<p> 889 Kelas {@link android.provider.ContactsContract} dan kelas-kelas tersarangnya adalah contoh 890 kelas kontrak. 891</p> 892<h2 id="Permissions">Mengimplementasikan Izin Penyedia Konten</h2> 893<p> 894 Izin dan akses untuk semua aspek sistem Android dijelaskan secara detail dalam 895 topik <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>. 896 Topik <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a> juga 897 menjelaskan keamanan dan izin terkait dengan berbagai tipe penyimpanan. 898 Singkatnya, poin-poin pentingnya adalah: 899</p> 900<ul> 901 <li> 902 Secara default, file data yang disimpan pada penyimpanan internal perangkat bersifat privat bagi 903 aplikasi dan penyedia Anda. 904 </li> 905 <li> 906 Database {@link android.database.sqlite.SQLiteDatabase} yang Anda buat bersifat privat bagi 907 aplikasi dan penyedia Anda. 908 </li> 909 <li> 910 Secara default, file data yang Anda simpan ke penyimpanan eksternal bersifat <em>publik</em> dan 911 <em>bisa dibaca secara global</em>. Anda tidak bisa menggunakan penyedia konten untuk membatasi akses ke file dalam 912 penyimpanan eksternal, karena aplikasi lain bisa menggunakan panggilan API untuk membaca dan menulis ke file tersebut. 913 </li> 914 <li> 915 Panggilan metode untuk membuka atau membuat file atau database SQLite pada 916 penyimpanan internal perangkat Anda berpotensi memberikan akses baca maupun tulis ke semua aplikasi lain. Jika Anda 917 menggunakan file atau database internal sebagai repository penyedia, dan Anda memberinya 918 akses "world-readable" (bisa dibaca secara global) atau "world-writeable" (bisa ditulis secara global), izin yang Anda atur untuk penyedia dalam 919 manifesnya tidak akan melindungi data Anda. Akses default untuk file dan database dalam 920 penyimpanan internal adalah "privat", dan untuk repository penyedia, tidak boleh Anda ubah. 921 </li> 922</ul> 923<p> 924 Jika Anda ingin menggunakan izin penyedia konten untuk mengontrol akses ke data Anda, maka Anda harus 925 menyimpan data Anda dalam file internal, database SQLite, atau "cloud" (misalnya, 926 di server jauh), dan Anda harus membuat file dan database tetap privat bagi aplikasi Anda. 927</p> 928<h3>Mengimplementasikan izin</h3> 929<p> 930 Semua aplikasi bisa membaca dari atau menulis ke penyedia Anda, sekalipun data yang mendasari adalah 931 privat, karena secara default penyedia Anda tidak mengatur izin. Untuk mengubahnya, 932 atur izin untuk penyedia dalam file manifes, dengan menggunakan atribut atau elemen anak 933 dari elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 934 <provider></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 <permission></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 <provider></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 <provider></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 <path-permission></a></code> dari 985 elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 986 <provider></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 <provider></a></code>, atau tambahkan satu atau beberapa elemen anak 1017 <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"> 1018 <grant-uri-permission></a></code> ke 1019 elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 1020 <provider></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 <grant-uri-permission></a></code> ke 1035 elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 1036 <provider></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 <provider></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 <provider></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 <provider></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> > <em>Apps</em> > <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> > <em>Apps</em> > <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 <provider></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