• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Aktivitas
2parent.title=Loader
3parent.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">
35LoaderCursor</a></li>
36     <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html">
37LoaderThrottle</a></li>
38   </ol>
39  </div>
40</div>
41
42<p>Diperkenalkan di Android 3.0, loader memudahkan pemuatan data asinkron
43dalam aktivitas atau fragmen. Loader memiliki karakteristik ini:</p>
44  <ul>
45    <li>Loader tersedia untuk setiap {@link android.app.Activity} dan {@link
46android.app.Fragment}.</li>
47    <li>Loader menyediakan pemuatan data asinkron.</li>
48    <li>Loader memantau sumber data mereka dan memberikan hasil baru bila
49konten berubah.</li>
50    <li>Loader secara otomatis menghubungkan kembali ke kursor loader lalu saat
51dibuat kembali setelah perubahan konfigurasi. Karena itu, loader tidak perlu melakukan query ulang
52datanya.</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
58loader 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
69android.content.Loader}. Ini membantu aplikasi mengelola
70operasi berjalan lebih lama bersamaan dengan daur hidup {@link android.app.Activity}
71atau {@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
77beberapa loader.</td>
78  </tr>
79  <tr>
80    <td>{@link android.app.LoaderManager.LoaderCallbacks}</td>
81    <td>Antarmuka callback untuk klien berinteraksi dengan {@link
82android.app.LoaderManager}. Misalnya, Anda menggunakan metode callback {@link
83android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
84untuk 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
89adalah kelas dasar untuk loader. Biasanya Anda akan menggunakan {@link
90android.content.CursorLoader}, namun Anda bisa menerapkan subkelas sendiri. Selagi
91loader aktif, loader harus memantau sumber datanya dan memberikan hasil
92baru 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
102android.database.Cursor}. Kelas ini mengimplementasikan protokol {@link
103android.content.Loader} dengan cara standar untuk query kursor,
104yang dibuat berdasarkan {@link android.content.AsyncTaskLoader} untuk melakukan query kursor
105pada thread latar belakang agar tidak memblokir UI aplikasi. Menggunakan loader
106ini merupakan cara terbaik untuk memuat data secara asinkron dari {@link
107android.content.ContentProvider}, sebagai ganti melakukan query terkelola melalui
108fragmen atau API aktivitas.</td>
109  </tr>
110</table>
111
112<p>Kelas dan antarmuka dalam tabel di atas merupakan komponen
113esensial yang akan Anda gunakan untuk mengimplementasikan loader dalam aplikasi Anda. Anda tidak memerlukan semuanya
114untuk setiap loader yang dibuat, namun Anda akan selalu memerlukan acuan ke {@link
115android.app.LoaderManager} untuk memulai loader dan implementasi
116kelas {@link android.content.Loader} seperti {@link
117android.content.CursorLoader}. Bagian berikut ini menunjukkan kepada Anda cara menggunakan
118kelas 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
122yang 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
127android.content.ContentProvider}. Atau, Anda dapat mengimplementasikan subkelas sendiri
128 dari {@link android.content.Loader} atau {@link android.content.AsyncTaskLoader} untuk
129memuat data dari beberapa sumber lain.</li>
130  <li>Implementasi untuk {@link android.app.LoaderManager.LoaderCallbacks}.
131Di sinilah Anda membuat loader baru dan mengelola acuan bagi loader
132yang ada.</li>
133<li>Cara menampilkan data loader, seperti {@link
134android.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
141android.content.Loader} dalam {@link android.app.Activity} atau
142{@link android.app.Fragment}. Hanya ada satu {@link
143android.app.LoaderManager} per aktivitas atau fragmen.</p>
144
145<p>Anda biasanya
146memulai {@link android.content.Loader} dalam metode {@link
147android.app.Activity#onCreate onCreate()} aktivitas, atau dalam metode
148{@link android.app.Fragment#onActivityCreated onActivityCreated()} fragmen. Anda
149melakukannya dengan cara berikut ini:</p>
150
151<pre>// Prepare the loader.  Either re-connect with an existing one,
152// or start a new one.
153getLoaderManager().initLoader(0, null, this);</pre>
154
155<p>Metode {@link android.app.LoaderManager#initLoader initLoader()} mengambil
156parameter 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
160pada saat pembuatan (dalam contoh ini <code>null</code>).</li>
161
162<li>Implementasi {@link android.app.LoaderManager.LoaderCallbacks}, yang
163akan dipanggil {@link android.app.LoaderManager} untuk melaporkan kejadian loader. Dalam contoh
164ini, kelas lokal mengimplementasikan antarmuka {@link
165android.app.LoaderManager.LoaderCallbacks}, sehingga meneruskan acuan
166ke dirinya sendiri, {@code this}.</li>
167</ul>
168<p>Panggilan {@link android.app.LoaderManager#initLoader initLoader()} memastikan bahwa loader
169telah 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
172kembali.</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()}.
176Di sinilah Anda mengimplementasikan kode untuk membuat instance dan mengembalikan loader baru.
177Untuk diskusi selengkapnya, lihat bagian <a href="#onCreateLoader">onCreateLoader</a>.</li>
178</ul>
179<p>Dalam hal ini, implementasi {@link android.app.LoaderManager.LoaderCallbacks}
180yang ditentukan akan dikaitkan dengan loader, dan akan dipanggil bila
181status loader berubah.  Jika saat panggilan ini status pemanggil sudah
182dimulai, dan loader yang diminta sudah ada dan telah menghasilkan
183datanya, maka sistem segera memanggil {@link
184android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
185(selama {@link android.app.LoaderManager#initLoader initLoader()}),
186sehingga Anda harus siap bila hal ini terjadi. Lihat <a href="#onLoadFinished">
187onLoadFinished</a> untuk diskusi selengkapnya mengenai callback ini</p>
188
189<p>Perhatikan bahwa metode {@link android.app.LoaderManager#initLoader initLoader()}
190mengembalikan {@link android.content.Loader} yang dibuat, namun Anda tidak
191perlu menangkap acuan ke sana. {@link android.app.LoaderManager} mengelola
192masa hidup loader secara otomatis. {@link android.app.LoaderManager}
193memulai dan menghentikan pemuatan jika perlu, dan menjaga status loader
194dan konten terkaitnya. Seperti yang tersirat di sini, Anda akan jarang berinteraksi dengan loader
195secara langsung (meskipun misalnya menggunakan metode loader untuk menyempurnakan perilaku
196loader, lihat contoh <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a>).
197Anda paling sering akan menggunakan metode {@link
198android.app.LoaderManager.LoaderCallbacks} untuk mengintervensi proses
199pemuatan 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
204ditampilkan di atas, loader yang ada akan digunakan dengan ID yang ditetapkan jika ada.
205Jika tidak ada, ID akan dibuat. Namun kadang-kadang Anda perlu membuang data lama
206dan mulai dari awal.</p>
207
208<p>Untuk membuang data lama, gunakan {@link
209android.app.LoaderManager#restartLoader restartLoader()}. Misalnya, implementasi
210{@link android.widget.SearchView.OnQueryTextListener} ini akan me-restart
211bila query pengguna berubah. Loader perlu di-restart
212agar dapat menggunakan filter pencarian yang telah direvisi untuk melakukan query baru:</p>
213
214<pre>
215public 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
227yang memungkinkan klien berinteraksi dengan {@link android.app.LoaderManager}. </p>
228<p>Loader, khususnya {@link android.content.CursorLoader}, diharapkan
229mempertahankan datanya setelah dihentikan. Ini memungkinkan aplikasi mempertahankan
230datanya di aktivitas atau metode {@link android.app.Activity#onStop
231onStop()} fragmen dan {@link android.app.Activity#onStart onStart()}, sehingga
232bila pengguna kembali ke aplikasi, mereka tidak harus menunggu data
233dimuat kembali. Anda menggunakan metode {@link android.app.LoaderManager.LoaderCallbacks}
234untuk mengetahui waktu membuat loader baru, dan memberi tahu aplikasi kapan
235berhenti menggunakan data loader.</p>
236
237<p>{@link android.app.LoaderManager.LoaderCallbacks} berisi metode
238ini:</p>
239<ul>
240  <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} —
241Membuat 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
250tidak 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
258android.app.LoaderManager#initLoader initLoader()}), ia akan memeriksa untuk mengetahui adanya
259loader yang ditetapkan oleh ID. Jika tidak ada, ia akan memicu metode {@link
260android.app.LoaderManager.LoaderCallbacks} {@link
261android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. Di
262sinilah Anda membuat loader baru. Biasanya ini adalah {@link
263android.content.CursorLoader}, namun Anda bisa mengimplementasikan sendiri subkelas {@link
264android.content.Loader}. </p>
265
266<p>Dalam contoh ini, metode callback {@link
267android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
268 akan membuat {@link android.content.CursorLoader}. Anda harus membuat
269{@link android.content.CursorLoader} menggunakan metode konstruktornya, yang
270memerlukan set informasi lengkap untuk melakukan query ke {@link
271android.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,
277diformat 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
280digantikan dengan nilai dari <em>selectionArgs</em>, agar muncul dalam
281pilihan. Nilai-nilai akan diikat sebagai String. </li>
282  <li><em>sortOrder</em> — Cara menyusun baris, diformat sebagai klausa SQL
283ORDER BY (tidak termasuk ORDER BY itu sendiri). Meneruskan <code>null</code> akan
284menggunakan 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.
289String mCurFilter;
290...
291public 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.
316Metode ini dijamin dipanggil sebelum pelepasan data terakhir
317yang disediakan untuk loader ini.  Di titik ini Anda harus menyingkirkan semua penggunaan
318data lama (karena akan segera dilepas), namun jangan melepas sendiri
319data tersebut karena loader memilikinya dan akan menanganinya.</p>
320
321
322<p>Loader akan melepas data setelah mengetahui bahwa aplikasi tidak
323lagi menggunakannya.  Misalnya, jika data adalah kursor dari {@link
324android.content.CursorLoader}, Anda tidak boleh memanggil {@link
325android.database.Cursor#close close()} sendiri. Jika kursor ditempatkan
326dalam {@link android.widget.CursorAdapter}, Anda harus menggunakan metode {@link
327android.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
335public 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
344tidak tersedia. Callback ini memungkinkan Anda mengetahui
345kapan data akan dilepas sehingga dapat menghapus acuannya ke callback.  </p>
346<p>Implementasi ini memanggil
347{@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()}
348dengan nilai <code>null</code>:</p>
349
350<pre>
351// This is the Adapter being used to display the list's data.
352SimpleCursorAdapter mAdapter;
353...
354
355public 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
366android.app.Fragment} yang menampilkan {@link android.widget.ListView} berisi
367hasil query terhadap penyedia konten kontak. Ia menggunakan {@link
368android.content.CursorLoader} untuk mengelola query pada penyedia.</p>
369
370<p>Agar aplikasi dapat mengakses kontak pengguna, seperti yang ditampilkan dalam contoh ini,
371manifesnya harus menyertakan izin
372{@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p>
373
374<pre>
375public 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
483mengilustrasikan cara menggunakan loader:</p>
484<ul>
485  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
486LoaderCursor</a> — Versi lengkap dari
487cuplikan 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
489mengurangi 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
493Contoh</a>. </p>
494
495