PagingSource dan Pager
Tentukan cara halaman dimuat.
PagingSource dan Pager adalah pelajaran Android Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Android Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Android Academy mencakup 4 pelajaran total.
Menentukan Cara Memuat Halaman
Untuk memuat halaman dari API jaringan, Anda menulis PagingSource. Komponen ini menjawab dua pertanyaan untuk Paging 3:
- Bagaimana cara memuat halaman untuk kunci tertentu?
- Jika pengguna menyegarkan daftar, dari mana pemuatan harus dilanjutkan?
Selanjutnya, bungkus komponen tersebut dalam Pager yang mengubahnya menjadi Flow<PagingData>.
Parameter Jenis PagingSource
PagingSource<Key, Value> menerima dua parameter jenis:
- Key - mengidentifikasi halaman. Untuk API berbasis nomor halaman, jenisnya adalah
Int; untuk API berbasis kursor, jenisnya adalah tokenString. - Value - jenis item, misalnya
Article.
import androidx.paging.PagingSource
import androidx.paging.PagingState
class ArticlePagingSource(
private val api: ArticleApi
) : PagingSource<Int, Article>() {
// implement load() and getRefreshKey()
}Mengimplementasikan load()
load() adalah fungsi suspend. Fungsi ini menerima params.key (halaman yang akan diambil) dan mengembalikan sebuah LoadResult.
Jika berhasil, kembalikan LoadResult.Page yang berisi item serta kunci sebelumnya dan berikutnya. Nilai null untuk suatu kunci berarti tidak ada halaman pada arah tersebut.
override suspend fun load(
params: LoadParams<Int>
): LoadResult<Int, Article> {
val page = params.key ?: 1 // first load has a null key
return try {
val response = api.getArticles(page = page, size = params.loadSize)
LoadResult.Page(
data = response.items,
prevKey = if (page == 1) null else page - 1,
nextKey = if (response.items.isEmpty()) null else page + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}Mengapa prevKey dan nextKey Penting
Paging menggunakan nextKey untuk memuat data ke depan saat pengguna menggulir ke bawah, dan prevKey untuk memuat data ke belakang, yang berguna saat memulai dari tengah daftar.
Mengembalikan null untuk nextKey memberi tahu Paging bahwa tidak ada halaman lagi, sehingga Paging berhenti meminta data. Jika hal ini terlupa, permintaan kosong tanpa akhir dapat terjadi.
// Stop forward paging when the server returns an empty page
nextKey = if (response.items.isEmpty()) null else page + 1
// Stop backward paging at the first page
prevKey = if (page == 1) null else page - 1Mengimplementasikan getRefreshKey()
Saat daftar disegarkan (tarik untuk menyegarkan atau pembatalan), Paging perlu mengetahui halaman mana yang harus dimuat ulang agar posisi pengguna tetap kurang lebih sama.
getRefreshKey() menggunakan anchorPosition saat ini - item yang paling dekat dengan area tampilan - untuk memilih kunci yang sesuai.
override fun getRefreshKey(state: PagingState<Int, Article>): Int? {
return state.anchorPosition?.let { anchor ->
val closestPage = state.closestPageToPosition(anchor)
closestPage?.prevKey?.plus(1)
?: closestPage?.nextKey?.minus(1)
}
}Menangani Kesalahan dengan Rapi
Bungkus pemanggilan jaringan dalam try/catch dan kembalikan LoadResult.Error(e) jika terjadi kegagalan. Paging menampilkan kondisi ini sebagai LoadState.Error di antarmuka pengguna, sehingga Anda dapat menampilkan tombol coba lagi.
Jangan pernah membiarkan pengecualian keluar dari load() - tangkap pengecualian tersebut dan ubah menjadi LoadResult.Error.
return try {
val response = api.getArticles(page = page, size = params.loadSize)
LoadResult.Page(
data = response.items,
prevKey = if (page == 1) null else page - 1,
nextKey = if (response.items.isEmpty()) null else page + 1
)
} catch (e: IOException) { // no network
LoadResult.Error(e)
} catch (e: HttpException) { // non-2xx response
LoadResult.Error(e)
}Membuat Pager
Pager menghubungkan PagingConfig Anda ke factory yang membuat PagingSource baru. Properti .flow-nya adalah Flow<PagingData> yang dikumpulkan oleh antarmuka pengguna.
Lambda factory harus membuat sumber baru setiap kali, karena Paging membatalkan dan membuat ulang sumber tersebut saat penyegaran.
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
class ArticleRepository(private val api: ArticleApi) {
fun articleStream(): Flow<PagingData<Article>> = Pager(
config = PagingConfig(pageSize = 20, prefetchDistance = 5),
pagingSourceFactory = { ArticlePagingSource(api) }
).flow
}cachedIn untuk ViewModel
Mengumpulkan PagingData adalah operasi satu kali; mengumpulkannya kembali akan memulai ulang pemuatan. Agar tetap bertahan selama perubahan konfigurasi dan memungkinkan beberapa pengumpul berbagi data, simpan aliran tersebut di viewModelScope menggunakan cachedIn.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.cachedIn
class ArticleViewModel(
repo: ArticleRepository
) : ViewModel() {
val articles = repo.articleStream()
.cachedIn(viewModelScope)
}loadSize vs pageSize
Perhatikan bahwa load() membaca params.loadSize, bukan langsung pageSize yang Anda konfigurasikan.
Pada pemuatan pertama, Paging mungkin meminta bagian awal yang lebih besar (dikendalikan oleh initialLoadSize dalam PagingConfig, dengan nilai bawaan tiga kali ukuran halaman). Selalu teruskan params.loadSize ke API Anda agar permintaan sesuai dengan jumlah data yang diharapkan Paging.
// Correct: respect the size Paging asks for
val response = api.getArticles(page = page, size = params.loadSize)
// PagingConfig can tune the first load:
PagingConfig(pageSize = 20, initialLoadSize = 40)API Berbasis Kursor
Tidak semua API menggunakan nomor halaman. Beberapa API mengembalikan kursor atau token yang menunjuk ke halaman berikutnya. Polanya sama - cukup ubah jenis Key menjadi String dan gunakan token dari respons.
class CursorArticleSource(
private val api: ArticleApi
) : PagingSource<String, Article>() {
override suspend fun load(
params: LoadParams<String>
): LoadResult<String, Article> {
val cursor = params.key // null on first load
return try {
val res = api.getArticles(cursor = cursor, size = params.loadSize)
LoadResult.Page(
data = res.items,
prevKey = null, // forward-only cursor
nextKey = res.nextCursor // null when exhausted
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<String, Article>) = null
}Menyatukan Semuanya
Sekarang Anda telah memiliki lapisan data lengkap: PagingSource yang memuat satu halaman, Pager yang mengalirkan halaman, dan ViewModel yang menyimpan aliran tersebut.
Lapisan antarmuka pengguna cukup mengumpulkan viewModel.articles - yang akan kita tampilkan pada pelajaran berikutnya menggunakan Compose LazyColumn.
// Data layer summary
// 1. ArticlePagingSource : PagingSource<Int, Article>
// 2. Pager(config, factory).flow -> Flow<PagingData<Article>>
// 3. ViewModel: repo.articleStream().cachedIn(viewModelScope)
// UI just collects viewModel.articlesPemeriksaan Singkat
Dalam PagingSource berbasis nomor halaman, apa yang ditandakan oleh pengembalian nextKey = null dari load()?
Ringkasan: PagingSource dan Pager
Anda telah membuat lapisan data untuk pemuatan halaman:
PagingSource<Key, Value>mengimplementasikanload()dangetRefreshKey()load()mengembalikanLoadResult.PagedenganprevKey/nextKey, atauLoadResult.Error- Kunci
nullmenghentikan pemuatan halaman pada arah tersebut Pager(config, factory).flowmenghasilkanFlow<PagingData>cachedIn(viewModelScope)mempertahankan data selama perubahan konfigurasi
Berikutnya: menampilkan aliran ini dalam daftar Compose.
Belajar Kotlin dengan tutor AI — gratis
Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.
- Kursus
- 36
- Pelajaran
- 152
Pertanyaan yang Sering Diajukan
Apakah pelajaran “PagingSource dan Pager” gratis?
Ya — teks lengkap “PagingSource dan Pager” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Android Academy, upgrade ke CoddyKit PRO. Kursus Android Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “PagingSource dan Pager”?
Tentukan cara halaman dimuat. Kamu berlatih Android Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Android Academy?
Tidak diperlukan pengalaman sebelumnya. Android Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “PagingSource dan Pager” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Android Academy ini?
Ya. Setiap pelajaran Android Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Mengapa Paging
- PagingSource dan Pager
- Paging dalam Daftar Compose
- RemoteMediator dan Caching