PagingSource ja Pager
Määritelkää, miten sivut ladataan.
PagingSource ja Pager on ilmainen Android Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Android Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Android Academy-kurssilla on yhteensä 4 oppituntia.
Sivujen lataustavan määrittäminen
Kun sivutatte dataa verkon API-rajapinnasta, kirjoitatte PagingSource-komponentin. Se vastaa kahteen Paging 3:n kysymykseen:
- Miten lataan tietyn avaimen mukaisen sivun?
- Mistä kohdasta jatkan, jos käyttäjä päivittää näkymän?
Sen jälkeen kääritte sen Pager-komponenttiin, joka muuntaa sen Flow<PagingData>-virraksi.
PagingSource-tyyppiparametrit
PagingSource<Key, Value> ottaa kaksi tyyppiparametria:
- Key – tunnistaa sivun. Sivunumeropohjaisessa API:ssa se on
Int; kursoripohjaisessa API:ssa se onString-tunniste. - Value – kohteiden tyyppi, esimerkiksi
Article.
import androidx.paging.PagingSource
import androidx.paging.PagingState
class ArticlePagingSource(
private val api: ArticleApi
) : PagingSource<Int, Article>() {
// implement load() and getRefreshKey()
}load()-funktion toteuttaminen
load() on suspend-funktio. Se vastaanottaa arvon params.key (haettavan sivun) ja palauttaa LoadResult-arvon.
Onnistuneessa tapauksessa palautatte LoadResult.Page-arvon, joka sisältää kohteet sekä edellisen ja seuraavan avaimen. Avaimen arvo null tarkoittaa, ettei kyseisessä suunnassa ole sivua.
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)
}
}Miksi prevKey ja nextKey ovat tärkeitä
Paging käyttää arvoa nextKey ladatakseen sivuja eteenpäin käyttäjän vierittäessä alaspäin ja arvoa prevKey ladatakseen sivuja taaksepäin (mikä on hyödyllistä, kun aloitetaan luettelon keskeltä).
Arvon null palauttaminen kentälle nextKey kertoo Pagingille, ettei sivuja ole enää jäljellä, joten se lopettaa pyynnöt. Jos tämä unohtuu, seurauksena voi olla loputtomia tyhjiä pyyntöjä.
// 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 - 1getRefreshKey()-funktion toteuttaminen
Kun luettelo päivitetään (vetämällä päivitettäessä tai mitätöinnin jälkeen), Pagingin on tiedettävä, mikä sivu ladataan uudelleen, jotta käyttäjä pysyy suunnilleen samassa kohdassa.
getRefreshKey() käyttää nykyistä anchorPosition-arvoa – näkymäporttia lähinnä olevaa kohdetta – valitakseen sopivan avaimen.
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)
}
}Virheiden hallinta siististi
Käärikää verkkokutsu try/catch-rakenteeseen ja palauttakaa virhetilanteessa LoadResult.Error(e). Paging välittää tämän käyttöliittymään LoadState.Error-tilana, joten voitte näyttää uudelleenyrityspainikkeen.
Älkää koskaan päästäkö poikkeusta karkaamaan load()-funktiosta – siepatkaa se ja muuntakaa se LoadResult.Error-arvoksi.
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)
}Pagerin luominen
Pager yhdistää PagingConfig-asetukset tehtaaseen, joka luo uuden PagingSource-komponentin. Sen .flow-ominaisuus on Flow<PagingData>, jonka käyttöliittymä kerää.
Tehdaslambda-funktion on luotava joka kerta uusi lähde, koska Paging mitätöi lähteen ja luo sen uudelleen päivityksen yhteydessä.
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 ViewModel-komponenteille
PagingData-arvon kerääminen on kertaluonteinen toiminto; uusi keräys käynnistää lataamisen uudelleen. Jotta data säilyy konfiguraatiomuutosten yli ja useat kerääjät voivat jakaa sen, tallentakaa virta välimuistiin viewModelScope-laajuudessa käyttämällä cachedIn-funktiota.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.cachedIn
class ArticleViewModel(
repo: ArticleRepository
) : ViewModel() {
val articles = repo.articleStream()
.cachedIn(viewModelScope)
}loadSize ja pageSize
Huomioikaa, että load() lukee arvon params.loadSize, ei suoraan määrittämäänne pageSize-arvoa.
Ensimmäisellä latauskerralla Paging saattaa pyytää suuremman alkujoukon. Sen kokoa hallitsee PagingConfig-asetuksen initialLoadSize, jonka oletusarvo on kolminkertainen sivukoko. Välittäkää API-rajapinnalle aina params.loadSize, jotta pyyntö vastaa Pagingin odottamaa vastausta.
// 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)Kursoripohjaiset API-rajapinnat
Kaikki API-rajapinnat eivät käytä sivunumeroita. Jotkin palauttavat kursorin tai tunnisteen, joka osoittaa seuraavaan sivuun. Menetelmä on sama – vaihtakaa vain Key-tyypiksi String ja käyttäkää vastauksesta saatua tunnistetta.
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
}Kokonaisuuden yhdistäminen
Teillä on nyt koko datakerros: yhden sivun lataava PagingSource, sivuja virtauttava Pager sekä virran välimuistiin tallentava ViewModel.
Käyttöliittymäkerros kerää yksinkertaisesti arvon viewModel.articles – seuraavalla oppitunnilla näytämme sen Compose-ympäristössä LazyColumn-komponentilla.
// 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.articlesPikatarkistus
Mitä sivunumeropohjaisessa PagingSource-komponentissa ilmaistaan palauttamalla nextKey = null load()-funktiosta?
Kertaus: PagingSource ja Pager
Rakensitte sivutuksen datakerroksen:
PagingSource<Key, Value>toteuttaa funktiotload()jagetRefreshKey()load()palauttaaLoadResult.Page-arvon kentilläprevKey/nextKeytai arvonLoadResult.Errornull-avain lopettaa sivutuksen kyseisessä suunnassaPager(config, factory).flowtuottaa arvonFlow<PagingData>cachedIn(viewModelScope)säilyttää datan konfiguraatiomuutosten yli
Seuraavaksi näytätte tämän virran Compose-luettelossa.
Opi Kotlin tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 36
- Oppitunnit
- 152
Usein kysytyt kysymykset
Onko oppitunti ”PagingSource ja Pager” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Android Academy-oppimispolun 3 oppituntia, myös oppitunnin “PagingSource ja Pager”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Android Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”PagingSource ja Pager”?
Määritelkää, miten sivut ladataan. Harjoittelet Android Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Android Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Android Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.
Kuinka kauan ”PagingSource ja Pager”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Android Academy-oppitunnilla?
Kyllä. Jokainen Android Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Miksi sivutus on tarpeen
- PagingSource ja Pager
- Sivutus Compose-luetteloissa
- RemoteMediator ja välimuistitus