12.1: Loader
Materi:
Salah satu alasan utama pengguna meninggalkan aplikasi adalah waktu startup. Penelitian menunjukkan bahwa jika sebuah aplikasi atau laman membutuhkan waktu lebih dari 3 detik untuk memuat, 40% pengguna akan meninggalkannya. Bagaimanapun juga, angka ini bervariasi bergantung pada penelitian, namun fakta yang tersebar luas adalah bahwa retensi pengguna berkaitan erat dengan kecepatan pemuatan aplikasi.
Waktu pemuatan aplikasi berkaitan langsung dengan apa saja yang terjadi pada thread UI. Semakin sedikit pekerjaan yang harus dilakukan thread UI Anda, semakin cepat pengguna melihat laman. Banyak faktor yang memengaruhi waktu startup aplikasi, dan Anda mengetahui selengkapnya tentang kinerja aplikasi dalam bab berikutnya. Salah satu tindakan besar dan nyata yang memengaruhi kinerja adalah berapa lama waktu yang diperlukan aplikasi Anda untuk memuat data.
Jika tahu persis asal data, Anda mungkin bisa mengoptimalkan dengan memuatnya sendiri. Jika data disediakan oleh penyedia materi, Anda mungkin tidak tahu backend-nya, dan mungkin tidak tahu apakah untuk pengguna tertentu akan ada data dalam jumlah kecil atau besar.
Solusinya adalah memuat sebagian besar atau semua data Anda di latar belakang, selagi menampilkan informasi yang relevan, yang disimpan secara lokal, kepada pengguna. Misalnya, Anda bisa menampilkan pada mereka informasi cuaca terbaru dalam cache, hingga mendapatkan informasi baru yang menampilkan cuaca saat ini untuk lokasi saat ini.
Loader adalah kelas keperluan khusus yang mengelola pemuatan dan pemuatan ulang asinkron di latar belakang dengan menggunakan AsyncTask.
Loader yang diperkenalkan di Android 3.0 memiliki karakteristik ini:
- Loader tersedia untuk setiap Aktivitas dan Fragmen.
- Loader menyediakan pemuatan data asinkron di latar belakang.
- Loader memantau sumber data mereka dan secara otomatis mengirimkan hasil baru bila materi berubah. Misalnya, jika Anda menampilkan data dalam RecyclerView, saat data yang mendasarinya berubah, CursorLoader secara otomatis memuat rangkaian data yang telah diperbarui, dan bila pemuatan selesai, bisa memberi tahu RecyclerView.Adapter untuk memperbarui apa yang ditampilkan kepada pengguna.
- Loader secara otomatis menghubungkan kembali ke kursor loader saat dibuat kembali setelah perubahan konfigurasi. Karena itu, loader tidak perlu melakukan kueri ulang datanya untuk ditampilkan kepada Anda.
Dalam bab sebelumnya Anda telah mempelajari tentang AsyncTask sebagai kelas serba guna untuk melakukan pekerjaan di latar belakang, dan menggunakan AsyncTaskLoader untuk menjaga data tetap tersedia bagi pengguna melalui perubahan konfigurasi.
Walaupun Anda bisa membuat loader khusus dengan menjadikan kelas Loader sebagai subkelas, kerangka kerja Android menyediakan CursorLoader yang langsung bisa digunakan dan berlaku untuk banyak kasus penggunaan. CursorLoader memperluas AsyncTaskLoader agar secara khusus bekerja dengan penyedia materi, sehingga banyak menghemat pekerjaan Anda.
Perhatikan, loader khusus bisa dibangun. Namun, karena sistem Android menyediakan solusi elegan yang banyak menghemat pekerjaan, pertimbangkan cara Anda menggunakannya seperti yang sudah ditentukan sebelum mengimplementasikan solusi sendiri dari awal. Sebelum menulis loader sendiri, selalu pertimbangkan apakah Anda bisa memperbaiki desain aplikasi untuk bekerja dengan CursorLoader.
Arsitektur loader
Seperti yang ditampilkan dalam diagram di bawah ini, loader akan mengganti panggilan kueri resolver materi ke penyedia materi. Diagram menampilkan versi sederhana dari arsitektur aplikasi bersama sebuah loader. Loader melakukan kueri untuk item dalam latar belakang. Loader mengamati data untuk Anda, dan jika data berubah, loader secara otomatis mendapatkan rangkaian data baru dan menyerahkannya ke adapter.
Mengimplementasikan CursorLoader
Aplikasi yang menggunakan loader biasanya menyertakan yang berikut ini:
- Sebuah Aktivitas atau Fragmen.
- Sebuah instance LoaderManager.
- Sebuah CursorLoader untuk memuat data yang dicadangkan oleh ContentProvider. Atau, Anda bisa mengimplementasikan subkelas Loader atau AsyncTaskLoader sendiri untuk memuat data dari beberapa sumber lainnya.
- Implementasi untuk LoaderManager.LoaderCallbacks. Inilah tempat membuat loader baru dan mengelola referensi Anda ke loader yang sudah ada.
- Cara menampilkan data loader, seperti SimpleCursorAdapter atau RecyclerViewAdapter.
- Sumber data, seperti ContentProvider (dengan CursorLoader).
LoaderManager
LoaderManager adalah kelas praktis yang mengelola semua loader Anda. Anda hanya perlu satu pengelola loader per aktivitas dan secara umum mendapatkannya pada onCreate() aktivitas, tempat mendaftarkan loader yang akan Anda gunakan.
Pengelola loader menangani pendaftaran sebuah observer pada penyedia materi, yang akan menerima callback bila data di penyedia materi berubah.
Satu-satunya panggilan untuk pengelola loader yang perlu Anda buat adalah untuk mendaftarkan loader, dan memulainya lagi saat Anda harus membuang semua data yang dimuat. Parameter pertama adalah ID loader, yang kedua adalah argumen opsional, dan yang ketiga adalah konteks tempat callback didefinisikan.
getLoaderManager().initLoader(0, null, this);
getLoaderManager().restartLoader(0, null, this);
LoaderManager.LoaderCallbacks
Untuk berinteraksi dengan loader, aktivitas Anda harus mengimplementasikan serangkaian callback yang ditetapkan dalam antarmuka LoaderCallbacks dari LoaderManager. Bila keadaan loader berubah, metode ini akan dipanggil karenanya. Metode tersebut adalah:
- onCreateLoader()—Dipanggil bila loader baru telah dibuat. Mengaitkan data dengan sumber data yang harus dimuat dan diamatinya. (Anda tidak harus melakukan tambahan apa pun bagi loader untuk mengamati sumber data.)
- onLoadFinished()—Dipanggil setiap kali loader selesai memuat. Memicu pembaruan data yang terlihat pengguna dalam metode ini.
- onLoaderReset()—Bila loader disetel ulang, Anda biasanya ingin melakukan invalidasi data yang saat ini ditahan hingga data baru dimuat.
Untuk mengimplementasikan callback ini, Anda perlu mengimplementasikan callback LoaderManager untuk tipe loader yang dimiliki. Untuk loader kursor, ubah tanda tangan aktivitas Anda seperti berikut, kemudian implementasikan callback.
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>
onCreateLoader()
Callback ini membuat instance dan mengembalikan instance loader baru dengan tipe yang diinginkan. Karena pengelola loader bisa mengelola beberapa loader sekaligus, argumen ID akan mengidentifikasi loader yang akan dibuat instance-nya. Setelah dibuat, loader akan mulai memuat data, dan akan mengamati tanggal perubahan Anda, serta memuat ulang jika diperlukan.
Untuk membuat CursorLoader, Anda memerlukan:
- uri—URI untuk materi yang diambil dari penyedia materi. URI mengidentifikasi penyedia materi dan data yang akan diamati loader.
- projection — Daftar kolom yang akan dikembalikan. Meneruskan nol akan mengembalikan semua kolom, jadi tidak efisien.
- selection — Filter yang mendeklarasikan baris yang akan dikembalikan, diformat sebagai klausa WHERE dari SQL (tidak termasuk WHERE itu sendiri). Meneruskan nol akan mengembalikan semua baris untuk URI yang diberikan.
- selectionArgs — Anda dapat menyertakan ?s dalam selection, yang akan digantikan dengan nilai dari selectionArgs, agar muncul dalam selection. Nilai-nilai akan diikat sebagai String.
- sortOrder — Cara menyusun baris, diformat sebagai klausa ORDER BY dari SQL (tidak termasuk ORDER BY itu sendiri). Meneruskan nol akan menggunakan urutan sortir default, yang mungkin tidak berurutan.
@Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { String queryUri = CONTENT_URI.toString(); String[] projection = new String[] {CONTENT_PATH}; return new CursorLoader(this, Uri.parse(queryUri), projection, null, null, null); }
Perhatikan betapa miripnya dengan inisiasi resolver materi:
Cursor cursor = mContext.getContentResolver().query(Uri.parse(uri),
projection, selectionClause, selectionArgs, sortOrder);
onLoadFinished()
Menetapkan apa yang terjadi dengan data setelah loader mendapatkannya. Dalam fungsi ini Anda harus:
- Merilis data lama.
- Menyimpan data baru dan, misalnya, menyediakannya untuk adapter Anda.
Loader kursor memantau data untuk Anda, jadi Anda tidak perlu, dan tidak seharusnya dalam keadaan apa pun, melakukannya sendiri.
Loader juga membersihkannya sendiri setelah dirinya sendiri, jadi Anda tidak perlu menutup kursor.
Jika Anda menggunakan RecyclerView untuk menampilkan data, yang perlu Anda lakukan hanyalah meneruskan data ke adapter bila pemuatan atau pemuatan ulang selesai.
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
mAdapter.setData(cursor);
}
onLoaderReset()
Dipanggil bila loader yang dibuat sebelumnya akan disetel ulang, sehingga datanya tidak tersedia. Anda harus membersihkan semua referensi ke data di saat ini. Lagi, jika Anda meneruskan data ke adapter untuk ditampilkan dalam RecyclerView, adapter akan melakukan pekerjaan sebenarnya, Anda hanya perlu menginstruksikannya.
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.setData(null);
}
Menggunakan data yang dikembalikan oleh loader
Dalam praktiknya, Anda menggunakan RecyclerView yang dikendalikan oleh adapter untuk menampilkan data yang diambil oleh loader. Setelah menerima data, loader menyerahkannya ke adapter melalui, misalnya, panggilan setData(). Metode setData() memperbarui variabel instance dalam adapter yang berisi set data terbaru, dan memberi tahu adapter bahwa ada data baru.
public void setData(Cursor cursor) {
mCursor = cursor;
notifyDataSetChanged();
}
Manfaat kursor
Anda mungkin sudah mengetahui bahwa database menggunakan kursor, penyedia materi menggunakan kursor, loader juga menggunakan kursor. Dengan menggunakan tipe data yang sama di seluruh backend, dan hanya mengekstraknya dalam adapter, tempat isi kursor dipersiapkan untuk ditampilkan, akan membuat backend seragam dengan antarmuka yang bersih. Hal ini akan memudahkan penulisan kode, memudahkan pengujian, dan memudahkan debug. Hal ini juga membuat kode lebih sederhana dan lebih pendek.
Lengkapi aplikasi dengan metode
Diagram berikut menampilkan metode dan tipe data yang menghubungkan aneka bagian aplikasi yang menggunakan:
- Database SQLite untuk menyimpan data, dan subkelas SQLiteOpenHelper untuk mengelola database.
- Penyedia materi untuk menyediakan data ke aplikasi ini (dan aplikasi lainnya).
- Loader untuk memuat data yang ditampilkan kepada pengguna.
- RecyclerView.Adapter yang menampilkan dan memperbarui data yang ditampilkan kepada pengguna di RecyclerView.
Kotak warna hijau menampilkan tumpukan panggilan dan perjalanan kursor melalui beberapa layer aplikasi untuk query(). Perhatikan bagaimana penyisipan, penghapusan, dan pembaruan tetap ditangani oleh resolver materi. Akan tetapi, loader akan memberitahukan setiap perubahan yang buat oleh operasi penyisipan, penghapusan, atau pembaruan, dan akan memuat ulang data bila diperlukan.
Praktik terkait
Latihan terkait dan dokumentasi praktik ada di Dasar-Dasar Developer Android: Praktik.
Ketahui selengkapnya
Dokumentasi Developer: