Android Academy · Ders

PagingSource ve Pager

Sayfaların nasıl yükleneceğini tanımlayın.

2. ders / 413 adım

PagingSource ve Pager, CoddyKit'te ücretsiz bir Android Academy dersidir. Bu, 4 dersinin 2. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Android Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Android Academy kursu toplamda 4 dersten oluşur.

Sayfaların Nasıl Yükleneceğini Tanımlama

Bir ağ API'sinden sayfalı veri almak için bir PagingSource yazarsınız. Bu, Paging 3 için iki soruyu yanıtlar:

  • Belirli bir anahtar için sayfayı nasıl yüklerim?
  • Kullanıcı yenilerse nereden devam etmeliyim?

Daha sonra bunu, bir Flow<PagingData>'ya dönüştüren bir Pager içine sararsınız.

PagingSource Tür Parametreleri

PagingSource<Key, Value> iki tür parametresi alır:

  • Key - bir sayfayı tanımlar. Sayfa numarası kullanan bir API için Int, imleç kullanan bir API için String belirtecidir.
  • Value - öğe türüdür; örneğin Article.
import androidx.paging.PagingSource
import androidx.paging.PagingState

class ArticlePagingSource(
    private val api: ArticleApi
) : PagingSource<Int, Article>() {
    // implement load() and getRefreshKey()
}

load() Uygulaması

load() bir suspend işlevidir. params.key (getirilecek sayfayı) alır ve bir LoadResult döndürür.

Başarılı olduğunda, öğelerle birlikte önceki ve sonraki anahtarları içeren LoadResult.Page döndürürsünüz. Bir anahtarın null olması, o yönde başka sayfa bulunmadığı anlamına gelir.

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)
    }
}

prevKey ve nextKey Neden Önemlidir

Paging, kullanıcı aşağı kaydırdıkça ileriye doğru yükleme yapmak için nextKey'i, geriye doğru yükleme yapmak içinse prevKey'i kullanır (listenin ortasından başlarken yararlıdır).

nextKey için null döndürmek, Paging'e başka sayfa olmadığını bildirir ve istek göndermeyi durdurur. Bunu unutmak, sonsuz sayıda boş isteğe neden olabilir.

// 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 - 1

getRefreshKey() Uygulaması

Liste yenilendiğinde (yenilemek için çekme veya geçersiz kılma), kullanıcının yaklaşık olarak aynı konumda kalması için Paging'in hangi sayfanın yeniden yükleneceğini bilmesi gerekir.

getRefreshKey(), geçerli anchorPosition değerini (görüntü alanına en yakın öğeyi) kullanarak uygun bir anahtar seçer.

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)
    }
}

Hataları Düzgün Yönetme

Ağ çağrısını bir try/catch bloğuna alın ve hata durumunda LoadResult.Error(e) döndürün. Paging bunu kullanıcı arayüzünde bir LoadState.Error olarak sunar; böylece yeniden deneme düğmesi gösterebilirsiniz.

Bir istisnanın load() dışına çıkmasına hiçbir zaman izin vermeyin; istisnayı yakalayıp LoadResult.Error değerine dönüştürün.

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)
}

Pager Oluşturma

Bir Pager, PagingConfig ayarlarınızı yeni bir PagingSource oluşturan bir fabrikaya bağlar. .flow özelliği, kullanıcı arayüzünün topladığı bir Flow<PagingData>'dır.

Fabrika lambda'sı her seferinde yeni bir kaynak oluşturmalıdır; çünkü Paging, yenileme sırasında kaynağı geçersiz kılar ve yeniden oluşturur.

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
}

ViewModels için cachedIn

PagingData toplama işlemi tek seferliktir; yeniden toplamak yüklemeyi baştan başlatır. Yapılandırma değişikliklerinden etkilenmemek ve birden fazla toplayıcının verileri paylaşmasını sağlamak için akışı viewModelScope içinde cachedIn ile önbelleğe alın.

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.cachedIn

class ArticleViewModel(
    repo: ArticleRepository
) : ViewModel() {
    val articles = repo.articleStream()
        .cachedIn(viewModelScope)
}

loadSize ve pageSize Karşılaştırması

load() işlevinin, doğrudan yapılandırdığınız pageSize değerini değil params.loadSize değerini okuduğuna dikkat edin.

İlk yüklemede Paging daha büyük bir başlangıç bölümü isteyebilir (PagingConfig içindeki initialLoadSize tarafından denetlenir ve varsayılan olarak sayfa boyutunun 3 katıdır). İsteğin Paging'in beklediği değerle eşleşmesi için API'nize her zaman params.loadSize değerini gönderin.

// 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)

İmleç Tabanlı API'ler

Her API sayfa numaralarını kullanmaz. Bazıları sonraki sayfayı gösteren bir imleç veya belirteç döndürür. Kalıp aynıdır; yalnızca Key türünü String olarak değiştirin ve yanıttaki belirteci kullanın.

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
}

Hepsini Birleştirme

Artık eksiksiz veri katmanına sahipsiniz: tek bir sayfayı yükleyen bir PagingSource, sayfaları akıtan bir Pager ve akışı önbelleğe alan bir ViewModel.

Kullanıcı arayüzü katmanı yalnızca viewModel.articles değerini toplar; bunu bir sonraki derste Compose LazyColumn ile görüntüleyeceğiz.

// 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.articles

Kısa Kontrol

Sayfa numarası kullanan bir PagingSource içinde load() işlevinden nextKey = null döndürülmesi neyi bildirir?

Özet: PagingSource ve Pager

Sayfalama için veri katmanını oluşturdunuz:

  • PagingSource<Key, Value>, load() ve getRefreshKey() işlevlerini uygular
  • load(), prevKey/nextKey içeren LoadResult.Page veya LoadResult.Error döndürür
  • null anahtar, ilgili yöndeki sayfalamayı durdurur
  • Pager(config, factory).flow, bir Flow<PagingData> üretir
  • cachedIn(viewModelScope), yapılandırma değişiklikleri boyunca verileri korur

Sırada: bu akışı bir Compose listesinde görüntülemek var.

Başlamak ücretsiz

Yapay zeka eğitmeniyle Kotlin öğren — ücretsiz

Tarayıcında gerçek kod yaz ve çalıştır, 7/24 yapay zeka eğitmeninden anında yardım al; web'de ya da uygulamada kaldığın yerden devam et.

Kurslar
36
Dersler
152

Sıkça Sorulan Sorular

“PagingSource ve Pager” dersi ücretsiz mi?

Evet — “PagingSource ve Pager” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Android Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Android Academy kursu toplamda 4 dersten oluşur.

“PagingSource ve Pager” dersinde ne öğreneceğim?

Sayfaların nasıl yükleneceğini tanımlayın. Android Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

Android Academy öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te Android Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 2. dersidir.

“PagingSource ve Pager” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu Android Academy dersinde kod yazıp çalıştırabilir miyim?

Evet. Her Android Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. Sayfalama Neden Kullanılır
  2. PagingSource ve Pager
  3. Compose Listelerinde Sayfalama
  4. RemoteMediator ve Önbelleğe Alma
← Android Academy Sayfasına Dön