Panduan ini dibuat berdasarkan ringkasan Library Paging, yang membahas cara menyesuaikan solusi pemuatan data aplikasi untuk memenuhi kebutuhan arsitektur aplikasi Anda.
Membuat daftar yang dapat diamati
Biasanya, kode UI Anda mengamati objek
LiveData<PagedList>
(atau,
jika Anda menggunakan RxJava2, objek
Flowable<PagedList>
atau Observable<PagedList>
), yang berada di
ViewModel
aplikasi Anda. Objek
yang dapat diamati ini membentuk koneksi antara presentasi dan konten dari
data daftar aplikasi Anda.
Untuk membuat salah satu objek
PagedList
yang dapat diamati ini, teruskan
instance
DataSource.Factory
ke
LivePagedListBuilder
atau objek
RxPagedListBuilder
. Objek DataSource
memuat
halaman untuk satu PagedList
. Class factory ini membuat instance baru
PagedList
sebagai respons terhadap pembaruan konten, seperti pembatalan validasi tabel database
dan pemuatan ulang jaringan. Library persistensi
Room dapat menyediakan objek DataSource.Factory
untuk Anda, atau Anda dapat membuatnya sendiri.
Cuplikan kode berikut menunjukkan cara membuat instance baru
LiveData<PagedList>
di class
ViewModel
aplikasi Anda menggunakan
kapabilitas
DataSource.Factory
-building
Room:
Kotlin
@Dao interface ConcertDao { // The Int type parameter tells Room to use a PositionalDataSource // object, with position-based loading under the hood. @Query("SELECT * FROM concerts ORDER BY date DESC") fun concertsByDate(): DataSource.Factory<Int, Concert> }
Java
@Dao public interface ConcertDao { // The Integer type parameter tells Room to use a PositionalDataSource // object, with position-based loading under the hood. @Query("SELECT * FROM concerts ORDER BY date DESC") DataSource.Factory<Integer, Concert> concertsByDate(); }
Kotlin
// The Int type argument corresponds to a PositionalDataSource object. val myConcertDataSource : DataSource.Factory<Int, Concert> = concertDao.concertsByDate() val concertList = myConcertDataSource.toLiveData(pageSize = 50)
Java
// The Integer type argument corresponds to a PositionalDataSource object. DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate(); LiveData<PagedList<Concert>> concertList = LivePagedListBuilder(myConcertDataSource, /* page size */ 50).build();
Menentukan konfigurasi paging Anda sendiri
Guna mengonfigurasi
LiveData<PagedList>
lebih lanjut untuk
kasus-kasus lanjutan, Anda juga dapat menentukan konfigurasi paging Anda sendiri. Secara khusus, Anda dapat
menentukan atribut berikut:
- Ukuran halaman: Jumlah item di setiap halaman.
- Jarak pengambilan data: Dengan memperhitungkan item terlihat terakhir di UI aplikasi, jumlah item di luar item terakhir yang harus diambil oleh Library Paging terlebih dahulu. Nilai ini harus beberapa kali lebih besar daripada ukuran halaman.
- Kehadiran placeholder: Menentukan apakah UI menampilkan placeholder untuk item daftar yang belum selesai dimuat. Untuk pembahasan tentang keuntungan dan kelemahan penggunaan placeholder, pelajari cara Menyediakan placeholder di UI.
Jika menginginkan kontrol lebih besar terkait kapan Library Paging memuat daftar dari
database aplikasi Anda, teruskan
objek Executor
kustom ke
LivePagedListBuilder
,
seperti ditunjukkan dalam cuplikan kode berikut:
Kotlin
val myPagingConfig = Config( pageSize = 50, prefetchDistance = 150, enablePlaceholders = true ) // The Int type argument corresponds to a PositionalDataSource object. val myConcertDataSource : DataSource.Factory<Int, Concert> = concertDao.concertsByDate() val concertList = myConcertDataSource.toLiveData( pagingConfig = myPagingConfig, fetchExecutor = myExecutor )
Java
PagedList.Config myPagingConfig = new PagedList.Config.Builder() .setPageSize(50) .setPrefetchDistance(150) .setEnablePlaceholders(true) .build(); // The Integer type argument corresponds to a PositionalDataSource object. DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate(); LiveData<PagedList<Concert>> concertList = new LivePagedListBuilder<>(myConcertDataSource, myPagingConfig) .setFetchExecutor(myExecutor) .build();
Memilih jenis sumber data yang benar
Penting untuk terhubung ke sumber data yang menangani struktur data sumber Anda paling baik:
- Gunakan
PageKeyedDataSource
jika halaman yang Anda muat menyematkan kunci berikutnya/sebelumnya. Misalnya, jika mengambil postingan media sosial dari jaringan, Anda mungkin perlu meneruskan tokennextPage
dari satu pemuatan ke pemuatan berikutnya. - Gunakan
ItemKeyedDataSource
jika Anda perlu menggunakan data dari item N untuk mengambil item N+1. Misalnya, jika mengambil komentar berangkai untuk aplikasi diskusi, Anda mungkin perlu meneruskan ID komentar terakhir untuk mendapatkan konten komentar berikutnya. - Gunakan
PositionalDataSource
jika Anda perlu mengambil halaman data dari lokasi mana pun yang Anda pilih di penyimpanan data. Class ini mendukung permintaan serangkaian item data mulai dari lokasi mana pun yang Anda pilih. Misalnya, permintaan ini dapat menampilkan 50 item data yang diawali dengan lokasi 1500.
Memberi tahu jika data tidak valid
Saat menggunakan Library Paging, lapisan data bertanggung jawab memberi tahu
lapisan lain di aplikasi Anda saat tabel atau baris menjadi usang. Untuk melakukannya, panggil
invalidate()
dari
class DataSource
yang telah
dipilih untuk aplikasi Anda.
Membuat sumber data Anda sendiri
Jika menggunakan solusi data lokal kustom, atau jika memuat data langsung dari
jaringan, Anda dapat mengimplementasikan salah satu
subclass DataSource
. Cuplikan
kode berikut menunjukkan sumber data yang dihitung dari waktu mulai
konser tertentu:
Kotlin
class ConcertTimeDataSource() : ItemKeyedDataSource<Date, Concert>() { override fun getKey(item: Concert) = item.startTime override fun loadInitial( params: LoadInitialParams<Date>, callback: LoadInitialCallback<Concert>) { val items = fetchItems(params.requestedInitialKey, params.requestedLoadSize) callback.onResult(items) } override fun loadAfter( params: LoadParams<Date>, callback: LoadCallback<Concert>) { val items = fetchItemsAfter( date = params.key, limit = params.requestedLoadSize) callback.onResult(items) } }
Java
public class ConcertTimeDataSource extends ItemKeyedDataSource<Date, Concert> { @NonNull @Override public Date getKey(@NonNull Concert item) { return item.getStartTime(); } @Override public void loadInitial(@NonNull LoadInitialParams<Date> params, @NonNull LoadInitialCallback<Concert> callback) { List<Concert> items = fetchItems(params.key, params.requestedLoadSize); callback.onResult(items); } @Override public void loadAfter(@NonNull LoadParams<Date> params, @NonNull LoadCallback<Concert> callback) { List<Concert> items = fetchItemsAfter(params.key, params.requestedLoadSize); callback.onResult(items); }
Selanjutnya, Anda dapat memuat data yang disesuaikan ini ke dalam objek PagedList
dengan membuat
subclass konkret dari
DataSource.Factory
. Cuplikan
kode berikut menunjukkan cara membuat instance baru sumber data
kustom yang ditentukan dalam cuplikan kode sebelumnya:
Kotlin
class ConcertTimeDataSourceFactory : DataSource.Factory<Date, Concert>() { val sourceLiveData = MutableLiveData<ConcertTimeDataSource>() var latestSource: ConcertDataSource? override fun create(): DataSource<Date, Concert> { latestSource = ConcertTimeDataSource() sourceLiveData.postValue(latestSource) return latestSource } }
Java
public class ConcertTimeDataSourceFactory extends DataSource.Factory<Date, Concert> { private MutableLiveData<ConcertTimeDataSource> sourceLiveData = new MutableLiveData<>(); private ConcertDataSource latestSource; @Override public DataSource<Date, Concert> create() { latestSource = new ConcertTimeDataSource(); sourceLiveData.postValue(latestSource); return latestSource; } }
Mempertimbangkan cara kerja pembaruan konten
Saat membuat objek
PagedList
yang dapat diamati, pertimbangkan cara
kerja update konten. Jika Anda memuat data secara langsung dari database
Room, update akan otomatis dikirim ke UI
aplikasi Anda.
Saat menggunakan API jaringan yang di-page, biasanya Anda memiliki interaksi pengguna, seperti
"geser untuk memuat ulang", yang berfungsi sebagai sinyal untuk membatalkan validasi
DataSource
yang terakhir Anda
gunakan. Selanjutnya, minta instance baru dari sumber data tersebut. Cuplikan kode
berikut menunjukkan perilaku ini:
Kotlin
class ConcertActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // ... concertTimeViewModel.refreshState.observe(this, Observer { // Shows one possible way of triggering a refresh operation. swipeRefreshLayout.isRefreshing = it == MyNetworkState.LOADING }) swipeRefreshLayout.setOnRefreshListener { concertTimeViewModel.invalidateDataSource() } } } class ConcertTimeViewModel(firstConcertStartTime: Date) : ViewModel() { val dataSourceFactory = ConcertTimeDataSourceFactory(firstConcertStartTime) val concertList: LiveData<PagedList<Concert>> = dataSourceFactory.toLiveData( pageSize = 50, fetchExecutor = myExecutor ) fun invalidateDataSource() = dataSourceFactory.sourceLiveData.value?.invalidate() }
Java
public class ConcertActivity extends AppCompatActivity { @Override public void onCreate(@Nullable Bundle savedInstanceState) { // ... viewModel.getRefreshState() .observe(this, new Observer<NetworkState>() { // Shows one possible way of triggering a refresh operation. @Override public void onChanged(@Nullable MyNetworkState networkState) { swipeRefreshLayout.isRefreshing = networkState == MyNetworkState.LOADING; } }; swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshListener() { @Override public void onRefresh() { viewModel.invalidateDataSource(); } }); } } public class ConcertTimeViewModel extends ViewModel { private LiveData<PagedList<Concert>> concertList; private DataSource<Date, Concert> mostRecentDataSource; public ConcertTimeViewModel(Date firstConcertStartTime) { ConcertTimeDataSourceFactory dataSourceFactory = new ConcertTimeDataSourceFactory(firstConcertStartTime); mostRecentDataSource = dataSourceFactory.create(); concertList = new LivePagedListBuilder<>(dataSourceFactory, 50) .setFetchExecutor(myExecutor) .build(); } public void invalidateDataSource() { mostRecentDataSource.invalidate(); } }
Menyediakan pemetaan data
Library Paging mendukung transformasi berbasis item dan berbasis halaman untuk item
yang dimuat oleh DataSource
.
Dalam cuplikan kode berikut, gabungan antara nama konser dan tanggal konser dipetakan ke satu string yang berisi nama dan tanggal:
Kotlin
class ConcertViewModel : ViewModel() { val concertDescriptions : LiveData<PagedList<String>> init { val concerts = database.allConcertsFactory() .map { "${it.name} - ${it.date}" } .toLiveData(pageSize = 50) } }
Java
public class ConcertViewModel extends ViewModel { private LiveData<PagedList<String>> concertDescriptions; public ConcertViewModel(MyDatabase database) { DataSource.Factory<Integer, Concert> factory = database.allConcertsFactory().map(concert -> concert.getName() + "-" + concert.getDate()); concertDescriptions = new LivePagedListBuilder<>( factory, /* page size */ 50).build(); } }
Cara ini dapat berguna jika Anda ingin menggabung, mengonversi, atau menyiapkan item setelah dimuat. Karena pekerjaan ini dilakukan di eksekutor pengambilan, Anda dapat melakukan pekerjaan yang berpotensi mahal, seperti membaca dari disk atau membuat kueri database terpisah.
Berikan masukan
Sampaikan masukan dan ide Anda kepada kami melalui resource berikut:
- Issue tracker
- Laporkan masalah agar kami dapat memperbaiki bug.
Referensi lainnya
Untuk mempelajari Library Paging lebih lanjut, pelajari referensi berikut.
Contoh
Codelab
Video
- Android Jetpack: mengelola daftar tanpa batas dengan RecyclerView dan Paging (Google I/O '18)
- Android Jetpack: Paging
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Bermigrasi ke Paging 3
- Ringkasan library Paging 2
- Menampilkan daftar yang di-page