Home | History | Annotate | Download | only in components
      1 page.title=Aktivitas
      2 parent.title=Loader
      3 parent.link=activities.html
      4 @jd:body
      5 <div id="qv-wrapper">
      6 <div id="qv">
      7     <h2>Dalam dokumen ini</h2>
      8     <ol>
      9     <li><a href="#summary">Rangkuman Loader API</a></li>
     10     <li><a href="#app">Menggunakan Loader dalam Aplikasi</a>
     11       <ol>
     12         <li><a href="#requirements"></a></li>
     13         <li><a href="#starting">Memulai Loader</a></li>
     14         <li><a href="#restarting">Me-restart Loader</a></li>
     15         <li><a href="#callback">Menggunakan Callback LoaderManager</a></li>
     16       </ol>
     17     </li>
     18     <li><a href="#example">Contoh</a>
     19        <ol>
     20          <li><a href="#more_examples">Contoh Selengkapnya</a></li>
     21         </ol>
     22     </li>
     23   </ol>
     24     
     25   <h2>Kelas-kelas utama</h2>
     26     <ol>
     27       <li>{@link android.app.LoaderManager}</li>
     28       <li>{@link android.content.Loader}</li>
     29 
     30     </ol>   
     31     
     32     <h2>Contoh-contoh terkait</h2>
     33    <ol>
     34      <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
     35 LoaderCursor</a></li>
     36      <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html">
     37 LoaderThrottle</a></li>
     38    </ol>
     39   </div>
     40 </div>
     41 
     42 <p>Diperkenalkan di Android 3.0, loader memudahkan pemuatan data asinkron
     43 dalam aktivitas atau fragmen. Loader memiliki karakteristik ini:</p>
     44   <ul>
     45     <li>Loader tersedia untuk setiap {@link android.app.Activity} dan {@link
     46 android.app.Fragment}.</li>
     47     <li>Loader menyediakan pemuatan data asinkron.</li>
     48     <li>Loader memantau sumber data mereka dan memberikan hasil baru bila
     49 konten berubah.</li>
     50     <li>Loader secara otomatis menghubungkan kembali ke kursor loader lalu saat
     51 dibuat kembali setelah perubahan konfigurasi. Karena itu, loader tidak perlu melakukan query ulang
     52 datanya.</li>
     53   </ul>
     54  
     55 <h2 id="summary">Rangkuman Loader API</h2>
     56 
     57 <p>Ada beberapa kelas dan antarmuka yang mungkin dilibatkan dalam menggunakan
     58 loader pada aplikasi. Semuanya dirangkum dalam tabel ini:</p>
     59 
     60 <table>
     61   <tr>
     62     <th>Kelas/Antarmuka</th>
     63     <th>Keterangan</th>
     64   </tr>
     65   <tr>
     66     <td>{@link android.app.LoaderManager}</td>
     67     <td>Kelas abstrak yang dikaitkan dengan {@link android.app.Activity} atau 
     68 {@link android.app.Fragment} untuk mengelola satu atau beberapa instance {@link
     69 android.content.Loader}.Ini membantu aplikasi mengelola
     70 operasi berjalan lebih lama bersamaan dengan daur hidup {@link android.app.Activity}
     71 atau {@link android.app.Fragment}; penggunaan paling umumnya adalah dengan 
     72 {@link android.content.CursorLoader}, akan tetapi aplikasi bebas menulis loader-nya
     73  sendiri untuk memuat tipe data lainnya.
     74     <br />
     75     <br />
     76     Hanya ada satu {@link android.app.LoaderManager} per aktivitas atau fragmen. Namun {@link android.app.LoaderManager} bisa memiliki
     77 beberapa loader.</td>
     78   </tr>
     79   <tr>
     80     <td>{@link android.app.LoaderManager.LoaderCallbacks}</td>
     81     <td>Antarmuka callback untuk klien berinteraksi dengan {@link
     82 android.app.LoaderManager}. Misalnya, Anda menggunakan metode callback {@link
     83 android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
     84 untuk membuat loader baru.</td>
     85   </tr>
     86   <tr>
     87     <td>{@link android.content.Loader}</td>
     88     <td>Kelas abstrak yang melakukan pemuatan data asinkron. Ini
     89 adalah kelas dasar untuk loader. Biasanya Anda akan menggunakan {@link
     90 android.content.CursorLoader}, namun Anda bisa menerapkan subkelas sendiri. Selagi
     91 loader aktif, loader harus memantau sumber datanya dan memberikan hasil
     92 baru bila konten berubah. </td>
     93   </tr>
     94   <tr>
     95     <td>{@link android.content.AsyncTaskLoader}</td>
     96     <td>Loader abstrak yang menyediakan {@link android.os.AsyncTask} untuk melakukan pekerjaan.</td>
     97   </tr>
     98   <tr>
     99     <td>{@link android.content.CursorLoader}</td>
    100     <td>Subkelas {@link android.content.AsyncTaskLoader} yang meng-query 
    101 {@link android.content.ContentResolver} dan mengembalikan {@link
    102 android.database.Cursor}. Kelas ini mengimplementasikan protokol {@link
    103 android.content.Loader} dengan cara standar untuk query kursor,
    104 yang dibuat berdasarkan {@link android.content.AsyncTaskLoader} untuk melakukan query kursor
    105 pada thread latar belakang agar tidak memblokir UI aplikasi. Menggunakan loader
    106 ini merupakan cara terbaik untuk memuat data secara asinkron dari {@link
    107 android.content.ContentProvider}, sebagai ganti melakukan query terkelola melalui
    108 fragmen atau API aktivitas.</td>
    109   </tr>
    110 </table>
    111 
    112 <p>Kelas dan antarmuka dalam tabel di atas merupakan komponen
    113 esensial yang akan Anda gunakan untuk mengimplementasikan loader dalam aplikasi Anda. Anda tidak memerlukan semuanya
    114 untuk setiap loader yang dibuat, namun Anda akan selalu memerlukan acuan ke {@link
    115 android.app.LoaderManager} untuk memulai loader dan implementasi
    116 kelas {@link android.content.Loader} seperti {@link
    117 android.content.CursorLoader}. Bagian berikut ini menunjukkan kepada Anda cara menggunakan
    118 kelas dan antarmuka ini dalam aplikasi.</p>
    119 
    120 <h2 id ="app">Menggunakan Loader dalam Aplikasi</h2>
    121 <p>Bagian ini menjelaskan cara menggunakan loader dalam aplikasi Android. Aplikasi
    122 yang menggunakan loader biasanya berisi yang berikut ini:</p>
    123 <ul>
    124   <li>{@link android.app.Activity} atau {@link android.app.Fragment}.</li>
    125   <li>Instance {@link android.app.LoaderManager}.</li>
    126   <li>{@link android.content.CursorLoader} akan memuat data yang didukung oleh {@link
    127 android.content.ContentProvider}. Atau, Anda dapat mengimplementasikan subkelas sendiri 
    128  dari {@link android.content.Loader} atau {@link android.content.AsyncTaskLoader} untuk
    129 memuat data dari beberapa sumber lain.</li>
    130   <li>Implementasi untuk {@link android.app.LoaderManager.LoaderCallbacks}.
    131 Di sinilah Anda membuat loader baru dan mengelola acuan bagi loader
    132 yang ada.</li> 
    133 <li>Cara menampilkan data loader, seperti {@link
    134 android.widget.SimpleCursorAdapter}.</li>
    135   <li>Sumber data, seperti {@link android.content.ContentProvider}, saat menggunakan 
    136 {@link android.content.CursorLoader}.</li>
    137 </ul>
    138 <h3 id="starting">Memulai Loader</h3>
    139 
    140 <p>{@link android.app.LoaderManager} mengelola satu atau beberapa instance {@link
    141 android.content.Loader} dalam {@link android.app.Activity} atau
    142 {@link android.app.Fragment}. Hanya ada satu {@link
    143 android.app.LoaderManager} per aktivitas atau fragmen.</p> 
    144 
    145 <p>Anda biasanya
    146 memulai {@link android.content.Loader} dalam metode {@link
    147 android.app.Activity#onCreate onCreate()} aktivitas, atau dalam metode 
    148 {@link android.app.Fragment#onActivityCreated onActivityCreated()} fragmen. Anda
    149 melakukannya dengan cara berikut ini:</p>
    150 
    151 <pre>// Prepare the loader.  Either re-connect with an existing one,
    152 // or start a new one.
    153 getLoaderManager().initLoader(0, null, this);</pre>
    154 
    155 <p>Metode {@link android.app.LoaderManager#initLoader initLoader()} mengambil
    156 parameter berikut:</p>
    157 <ul>
    158   <li>ID unik yang mengidentifikasi loader. Dalam contoh ini, ID-nya adalah 0.</li>
    159 <li>Argumen opsional untuk dipasok ke loader
    160 pada saat pembuatan (dalam contoh ini <code>null</code>).</li> 
    161 
    162 <li>Implementasi {@link android.app.LoaderManager.LoaderCallbacks}, yang
    163 akan dipanggil {@link android.app.LoaderManager} untuk melaporkan kejadian loader. Dalam contoh
    164 ini, kelas lokal mengimplementasikan antarmuka {@link
    165 android.app.LoaderManager.LoaderCallbacks}, sehingga meneruskan acuan
    166 ke dirinya sendiri, {@code this}.</li> 
    167 </ul>
    168 <p>Panggilan {@link android.app.LoaderManager#initLoader initLoader()} memastikan bahwa loader
    169 telah dimulai dan aktif. Ia memiliki dua kemungkinan hasil:</p>
    170 <ul>
    171   <li>Jika loader yang disebutkan oleh ID sudah ada, loader yang dibuat terakhir akan digunakan
    172 kembali.</li>
    173   <li>Jika loader yang disebutkan oleh ID <em>tidak</em> ada,
    174 {@link android.app.LoaderManager#initLoader initLoader()} akan memicu metode
    175 {@link android.app.LoaderManager.LoaderCallbacks} {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}.
    176 Di sinilah Anda mengimplementasikan kode untuk membuat instance dan mengembalikan loader baru.
    177 Untuk diskusi selengkapnya, lihat bagian <a href="#onCreateLoader">onCreateLoader</a>.</li>
    178 </ul>
    179 <p>Dalam hal ini, implementasi {@link android.app.LoaderManager.LoaderCallbacks}
    180 yang ditentukan akan dikaitkan dengan loader, dan akan dipanggil bila
    181 status loader berubah.  Jika saat panggilan ini status pemanggil sudah
    182 dimulai, dan loader yang diminta sudah ada dan telah menghasilkan
    183 datanya, maka sistem segera memanggil {@link
    184 android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    185 (selama {@link android.app.LoaderManager#initLoader initLoader()}),
    186 sehingga Anda harus siap bila hal ini terjadi. Lihat <a href="#onLoadFinished">
    187 onLoadFinished</a> untuk diskusi selengkapnya mengenai callback ini</p>
    188 
    189 <p>Perhatikan bahwa metode {@link android.app.LoaderManager#initLoader initLoader()}
    190 mengembalikan {@link android.content.Loader} yang dibuat, namun Anda tidak
    191 perlu menangkap acuan ke sana. {@link android.app.LoaderManager} mengelola
    192 masa hidup loader secara otomatis. {@link android.app.LoaderManager}
    193 memulai dan menghentikan pemuatan jika perlu, dan menjaga status loader
    194 dan konten terkaitnya. Seperti yang tersirat di sini, Anda akan jarang berinteraksi dengan loader
    195 secara langsung (meskipun misalnya menggunakan metode loader untuk menyempurnakan perilaku
    196 loader, lihat contoh <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a>). 
    197 Anda paling sering akan menggunakan metode {@link
    198 android.app.LoaderManager.LoaderCallbacks} untuk mengintervensi proses
    199 pemuatan saat terjadi kejadian tertentu. Untuk diskusi selengkapnya mengenai topik ini, lihat <a href="#callback">Menggunakan Callback LoaderManager</a>.</p>
    200 
    201 <h3 id="restarting">Me-restart Loader</h3>
    202 
    203 <p>Bila Anda menggunakan {@link android.app.LoaderManager#initLoader initLoader()}, seperti
    204 ditampilkan di atas, loader yang ada akan digunakan dengan ID yang ditetapkan jika ada.
    205 Jika tidak ada, ID akan dibuat. Namun kadang-kadang Anda perlu membuang data lama
    206 dan mulai dari awal.</p>
    207 
    208 <p>Untuk membuang data lama, gunakan {@link
    209 android.app.LoaderManager#restartLoader restartLoader()}. Misalnya, implementasi
    210 {@link android.widget.SearchView.OnQueryTextListener} ini akan me-restart
    211 bila query pengguna berubah. Loader perlu di-restart
    212 agar dapat menggunakan filter pencarian yang telah direvisi untuk melakukan query baru:</p>
    213 
    214 <pre>
    215 public boolean onQueryTextChanged(String newText) {
    216     // Called when the action bar search text has changed.  Update
    217     // the search filter, and restart the loader to do a new query
    218     // with this filter.
    219     mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    220     getLoaderManager().restartLoader(0, null, this);
    221     return true;
    222 }</pre>
    223 
    224 <h3 id="callback">Menggunakan Callback LoaderManager</h3>
    225 
    226 <p>{@link android.app.LoaderManager.LoaderCallbacks} adalah antarmuka callback
    227 yang memungkinkan klien berinteraksi dengan {@link android.app.LoaderManager}. </p>
    228 <p>Loader, khususnya {@link android.content.CursorLoader}, diharapkan
    229 mempertahankan datanya setelah dihentikan. Ini memungkinkan aplikasi mempertahankan
    230 datanya di aktivitas atau metode {@link android.app.Activity#onStop
    231 onStop()} fragmen dan {@link android.app.Activity#onStart onStart()}, sehingga
    232 bila pengguna kembali ke aplikasi, mereka tidak harus menunggu data
    233 dimuat kembali. Anda menggunakan metode {@link android.app.LoaderManager.LoaderCallbacks}
    234 untuk mengetahui waktu membuat loader baru, dan memberi tahu aplikasi kapan
    235 berhenti menggunakan data loader.</p>
    236 
    237 <p>{@link android.app.LoaderManager.LoaderCallbacks} berisi metode
    238 ini:</p>
    239 <ul>
    240   <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} 
    241 Membuat instance dan mengembalikan {@link android.content.Loader} baru untuk ID yang diberikan.
    242 </li></ul>
    243 <ul>
    244   <li> {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    245  Dipanggil bila loader yang dibuat sebelumnya selesai dimuat.
    246 </li></ul>
    247 <ul>
    248   <li>{@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}  
    249      Dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya
    250 tidak tersedia.
    251 </li>
    252 </ul>
    253 <p>Metode ini dijelaskan lebih detail dalam bagian berikutnya.</p>
    254 
    255 <h4 id ="onCreateLoader">onCreateLoader</h4>
    256 
    257 <p>Saat Anda mencoba mengakses loader (misalnya, melalui {@link
    258 android.app.LoaderManager#initLoader initLoader()}), ia akan memeriksa untuk mengetahui adanya
    259 loader yang ditetapkan oleh ID. Jika tidak ada, ia akan memicu metode {@link
    260 android.app.LoaderManager.LoaderCallbacks} {@link
    261 android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. Di
    262 sinilah Anda membuat loader baru. Biasanya ini adalah {@link
    263 android.content.CursorLoader}, namun Anda bisa mengimplementasikan sendiri subkelas {@link
    264 android.content.Loader}. </p>
    265 
    266 <p>Dalam contoh ini, metode callback {@link
    267 android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
    268  akan membuat {@link android.content.CursorLoader}. Anda harus membuat
    269 {@link android.content.CursorLoader} menggunakan metode konstruktornya, yang
    270 memerlukan set informasi lengkap untuk melakukan query ke {@link
    271 android.content.ContentProvider}. Secara khusus, ia memerlukan:</p>
    272 <ul>
    273   <li><em>uri</em>  URI untuk konten yang akan diambil. </li>
    274   <li><em>projection</em>  Daftar berisi kolom yang akan dikembalikan. Meneruskan
    275 <code>null</code> akan mengembalikan semua kolom, jadi tidak efisien. </li>
    276   <li><em>selection</em>  Filter yang mendeklarasikan baris yang akan dikembalikan,
    277 diformat sebagai klausa SQL WHERE (tidak termasuk WHERE itu sendiri). Meneruskan
    278 <code>null</code> akan mengembalikan semua baris untuk URI yang diberikan. </li>
    279   <li><em>selectionArgs</em>  Anda dapat menyertakan ?s dalam pilihan, yang akan
    280 digantikan dengan nilai dari <em>selectionArgs</em>, agar muncul dalam
    281 pilihan. Nilai-nilai akan diikat sebagai String. </li>
    282   <li><em>sortOrder</em>  Cara menyusun baris, diformat sebagai klausa SQL
    283 ORDER BY (tidak termasuk ORDER BY itu sendiri). Meneruskan <code>null</code> akan
    284 menggunakan urutan sortir default, yang mungkin tidak berurutan.</li>
    285 </ul>
    286 <p>Misalnya:</p>
    287 <pre>
    288  // If non-null, this is the current filter the user has provided.
    289 String mCurFilter;
    290 ...
    291 public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
    292     // This is called when a new Loader needs to be created. This
    293     // sample only has one Loader, so we don't care about the ID.
    294     // First, pick the base URI to use depending on whether we are
    295     // currently filtering.
    296     Uri baseUri;
    297   if (mCurFilter != null) {
    298     baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
    299           Uri.encode(mCurFilter));
    300   } else {
    301     baseUri = Contacts.CONTENT_URI;
    302   }
    303 
    304   // Now create and return a CursorLoader that will take care of
    305   // creating a Cursor for the data being displayed.
    306   String select = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
    307       + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
    308       + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
    309   return new CursorLoader(getActivity(), baseUri,
    310       CONTACTS_SUMMARY_PROJECTION, select, null,
    311       Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
    312 }</pre>
    313 <h4 id="onLoadFinished">onLoadFinished</h4>
    314 
    315 <p>Metode ini dipanggil bila loader yang dibuat sebelumnya selesai dimuat.
    316 Metode ini dijamin dipanggil sebelum pelepasan data terakhir
    317 yang disediakan untuk loader ini.  Di titik ini Anda harus menyingkirkan semua penggunaan
    318 data lama (karena akan segera dilepas), namun jangan melepas sendiri
    319 data tersebut karena loader memilikinya dan akan menanganinya.</p>
    320 
    321 
    322 <p>Loader akan melepas data setelah mengetahui bahwa aplikasi tidak
    323 lagi menggunakannya.  Misalnya, jika data adalah kursor dari {@link
    324 android.content.CursorLoader}, Anda tidak boleh memanggil {@link
    325 android.database.Cursor#close close()} sendiri. Jika kursor ditempatkan 
    326 dalam {@link android.widget.CursorAdapter}, Anda harus menggunakan metode {@link
    327 android.widget.SimpleCursorAdapter#swapCursor swapCursor()} agar
    328 {@link android.database.Cursor} lama tidak ditutup. Misalnya:</p>
    329 
    330 <pre>
    331 // This is the Adapter being used to display the list's data.<br
    332 />SimpleCursorAdapter mAdapter;
    333 ...
    334 
    335 public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
    336     // Swap the new cursor in. (The framework will take care of closing the
    337     // old cursor once we return.)
    338     mAdapter.swapCursor(data);
    339 }</pre>
    340 
    341 <h4 id="onLoaderReset">onLoaderReset</h4>
    342 
    343 <p>Metode ini dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya
    344 tidak tersedia. Callback ini memungkinkan Anda mengetahui
    345 kapan data akan dilepas sehingga dapat menghapus acuannya ke callback. </p>
    346 <p>Implementasi ini memanggil 
    347 {@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()}
    348 dengan nilai <code>null</code>:</p>
    349 
    350 <pre>
    351 // This is the Adapter being used to display the list's data.
    352 SimpleCursorAdapter mAdapter;
    353 ...
    354 
    355 public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
    356     // This is called when the last Cursor provided to onLoadFinished()
    357     // above is about to be closed. We need to make sure we are no
    358     // longer using it.
    359     mAdapter.swapCursor(null);
    360 }</pre>
    361 
    362 
    363 <h2 id="example">Contoh</h2>
    364 
    365 <p>Sebagai contoh, berikut ini adalah implementasi penuh {@link
    366 android.app.Fragment} yang menampilkan {@link android.widget.ListView} berisi
    367 hasil query terhadap penyedia konten kontak. Ia menggunakan {@link
    368 android.content.CursorLoader} untuk mengelola query pada penyedia.</p>
    369  
    370 <p>Agar aplikasi dapat mengakses kontak pengguna, seperti yang ditampilkan dalam contoh ini,
    371 manifesnya harus menyertakan izin
    372 {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p>
    373 
    374 <pre>
    375 public static class CursorLoaderListFragment extends ListFragment
    376     implements OnQueryTextListener, LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
    377 
    378     // This is the Adapter being used to display the list's data.
    379   SimpleCursorAdapter mAdapter;
    380 
    381   // If non-null, this is the current filter the user has provided.
    382   String mCurFilter;
    383 
    384   @Override public void onActivityCreated(Bundle savedInstanceState) {
    385     super.onActivityCreated(savedInstanceState);
    386 
    387     // Give some text to display if there is no data. In a real
    388     // application this would come from a resource.
    389     setEmptyText(&quot;No phone numbers&quot;);
    390 
    391     // We have a menu item to show in action bar.
    392     setHasOptionsMenu(true);
    393 
    394     // Create an empty adapter we will use to display the loaded data.
    395     mAdapter = new SimpleCursorAdapter(getActivity(),
    396         android.R.layout.simple_list_item_2, null,
    397         new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
    398         new int[] { android.R.id.text1, android.R.id.text2 }, 0);
    399     setListAdapter(mAdapter);
    400 
    401     // Prepare the loader. Either re-connect with an existing one,
    402     // or start a new one.
    403     getLoaderManager().initLoader(0, null, this);
    404   }
    405 
    406   @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    407     // Place an action bar item for searching.
    408     MenuItem item = menu.add(&quot;Search&quot;);
    409     item.setIcon(android.R.drawable.ic_menu_search);
    410     item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    411     SearchView sv = new SearchView(getActivity());
    412     sv.setOnQueryTextListener(this);
    413     item.setActionView(sv);
    414   }
    415 
    416   public boolean onQueryTextChange(String newText) {
    417     // Called when the action bar search text has changed. Update
    418     // the search filter, and restart the loader to do a new query
    419     // with this filter.
    420     mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    421     getLoaderManager().restartLoader(0, null, this);
    422     return true;
    423   }
    424 
    425   @Override public boolean onQueryTextSubmit(String query) {
    426     // Don't care about this.
    427     return true;
    428   }
    429 
    430   @Override public void onListItemClick(ListView l, View v, int position, long id) {
    431     // Insert desired behavior here.
    432     Log.i(&quot;FragmentComplexList&quot;, &quot;Item clicked: &quot; + id);
    433   }
    434 
    435   // These are the Contacts rows that we will retrieve.
    436   static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
    437     Contacts._ID,
    438     Contacts.DISPLAY_NAME,
    439     Contacts.CONTACT_STATUS,
    440     Contacts.CONTACT_PRESENCE,
    441     Contacts.PHOTO_ID,
    442     Contacts.LOOKUP_KEY,
    443   };
    444   public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
    445     // This is called when a new Loader needs to be created. This
    446     // sample only has one Loader, so we don't care about the ID.
    447     // First, pick the base URI to use depending on whether we are
    448     // currently filtering.
    449     Uri baseUri;
    450     if (mCurFilter != null) {
    451       baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
    452           Uri.encode(mCurFilter));
    453     } else {
    454       baseUri = Contacts.CONTENT_URI;
    455     }
    456 
    457     // Now create and return a CursorLoader that will take care of
    458     // creating a Cursor for the data being displayed.
    459     String select = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
    460         + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
    461         + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
    462     return new CursorLoader(getActivity(), baseUri,
    463         CONTACTS_SUMMARY_PROJECTION, select, null,
    464         Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
    465   }
    466 
    467   public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
    468     // Swap the new cursor in. (The framework will take care of closing the
    469     // old cursor once we return.)
    470     mAdapter.swapCursor(data);
    471   }
    472 
    473   public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
    474     // This is called when the last Cursor provided to onLoadFinished()
    475     // above is about to be closed. We need to make sure we are no
    476     // longer using it.
    477     mAdapter.swapCursor(null);
    478   }
    479 }</pre>
    480 <h3 id="more_examples">Contoh Selengkapnya</h3>
    481 
    482 <p>Ada beberapa contoh berbeda dalam <strong>ApiDemos</strong> yang
    483 mengilustrasikan cara menggunakan loader:</p>
    484 <ul>
    485   <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
    486 LoaderCursor</a>  Versi lengkap dari
    487 cuplikan yang ditampilkan di atas.</li>
    488   <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a>  Contoh cara penggunaan throttling untuk
    489 mengurangi jumlah query dari penyedia konten saat datanya berubah.</li>
    490 </ul>
    491 
    492 <p>Untuk informasi tentang mengunduh dan menginstal contoh SDK, lihat <a href="http://developer.android.com/resources/samples/get.html"> Mendapatkan
    493 Contoh</a>. </p>
    494 
    495