PagingSource | API reference | Android Developers (original) (raw)
- Cmn
abstract class PagingSource<Key : Any, Value : Any>
Base class for an abstraction of pageable static data from some source, where loading pages of data is typically an expensive operation. Some examples of common [PagingSource](/reference/kotlin/androidx/paging/PagingSource)s might be from network or from a database.
An instance of a [PagingSource](/reference/kotlin/androidx/paging/PagingSource) is used to load pages of data for an instance of [PagingData](/reference/kotlin/androidx/paging/PagingData).
A [PagingData](/reference/kotlin/androidx/paging/PagingData) can grow as it loads more data, but the data loaded cannot be updated. If the underlying data set is modified, a new [PagingSource](/reference/kotlin/androidx/paging/PagingSource) / [PagingData](/reference/kotlin/androidx/paging/PagingData) pair must be created to represent an updated snapshot of the data.
Loading Pages
[PagingData](/reference/kotlin/androidx/paging/PagingData) queries data from its [PagingSource](/reference/kotlin/androidx/paging/PagingSource) in response to loading hints generated as the user scrolls in a RecyclerView.
To control how and when a [PagingData](/reference/kotlin/androidx/paging/PagingData) queries data from its [PagingSource](/reference/kotlin/androidx/paging/PagingSource), see [PagingConfig](/reference/kotlin/androidx/paging/PagingConfig), which defines behavior such as [PagingConfig.pageSize](/reference/kotlin/androidx/paging/PagingConfig#pageSize%28%29) and [PagingConfig.prefetchDistance](/reference/kotlin/androidx/paging/PagingConfig#prefetchDistance%28%29).
Updating Data
A [PagingSource](/reference/kotlin/androidx/paging/PagingSource) / [PagingData](/reference/kotlin/androidx/paging/PagingData) pair is a snapshot of the data set. A new [PagingData](/reference/kotlin/androidx/paging/PagingData) / [PagingData](/reference/kotlin/androidx/paging/PagingData) must be created if an update occurs, such as a reorder, insert, delete, or content update occurs. A [PagingSource](/reference/kotlin/androidx/paging/PagingSource) must detect that it cannot continue loading its snapshot (for instance, when Database query notices a table being invalidated), and call [invalidate](/reference/kotlin/androidx/paging/PagingSource#invalidate%28%29). Then a new [PagingSource](/reference/kotlin/androidx/paging/PagingSource) / [PagingData](/reference/kotlin/androidx/paging/PagingData) pair would be created to represent data from the new state of the database query.
Presenting Data to UI
To present data loaded by a [PagingSource](/reference/kotlin/androidx/paging/PagingSource) to a RecyclerView, create an instance of [Pager](/reference/kotlin/androidx/paging/Pager), which provides a stream of [PagingData](/reference/kotlin/androidx/paging/PagingData) that you may collect from and submit to a androidx.paging.PagingDataAdapter.
import androidx.paging.PagingSource import androidx.paging.PagingSource.LoadResult import androidx.paging.PagingState
/**
Sample page-keyed PagingSource, which uses Int page number to load pages.
Loads Items from network requests via Retrofit to a backend service.
Note that the key type is Int, since we're using page number to load a page. */ class MyPagingSource(val myBackend: MyBackendService) : PagingSource<Int, Item>() { override suspend fun load(params: LoadParams): LoadResult<Int, Item> {
// Retrofit calls that return the body type throw either IOException for network // failures, or HttpException for any non-2xx HTTP status codes. This code reports all // errors to the UI, but you can inspect/wrap the exceptions to provide more context. return try { // Key may be null during a refresh, if no explicit key is passed into Pager // construction. Use 0 as default, because our API is indexed started at index 0 val pageNumber = params.key ?: 0 // Suspending network load via Retrofit. This doesn't need to be wrapped in a // withContext(Dispatcher.IO) { ... } block since Retrofit's Coroutine // CallAdapter dispatches on a worker thread. val response = myBackend.searchItems(pageNumber) // Since 0 is the lowest page number, return null to signify no more pages should // be loaded before it. val prevKey = if (pageNumber > 0) pageNumber - 1 else null // This API defines that it's out of data when a page returns empty. When out of // data, we return `null` to signify no more pages should be loaded val nextKey = if (response.items.isNotEmpty()) pageNumber + 1 else null LoadResult.Page(data = response.items, prevKey = prevKey, nextKey = nextKey) } catch (e: IOException) { LoadResult.Error(e) } catch (e: HttpException) { LoadResult.Error(e) }}
override fun getRefreshKey(state: PagingState<Int, Item>): Int? { return state.anchorPosition?.let { state.closestPageToPosition(it)?.prevKey?.plus(1) ?: state.closestPageToPosition(it)?.nextKey?.minus(1) } }
}
import androidx.paging.PagingSource import androidx.paging.PagingSource.LoadResult import androidx.paging.PagingState
/**
Sample item-keyed [PagingSource], which uses String tokens to load pages.
Loads Items from network requests via Retrofit to a backend service. */ class MyPagingSource(val myBackend: MyBackendService) : PagingSource<String, Item>() { override suspend fun load(params: LoadParams): LoadResult<String, Item> { // Retrofit calls that return the body type throw either IOException for network // failures, or HttpException for any non-2xx HTTP status codes. This code reports all // errors to the UI, but you can inspect/wrap the exceptions to provide more context. return try { // Suspending network load via Retrofit. This doesn't need to be wrapped in a // withContext(Dispatcher.IO) { ... } block since Retrofit's Coroutine // CallAdapter dispatches on a worker thread. val response = myBackend.searchItems(params.key) LoadResult.Page( data = response.items, prevKey = response.prev, nextKey = response.next, ) } catch (e: IOException) { LoadResult.Error(e) } catch (e: HttpException) { LoadResult.Error(e) } }
override fun getRefreshKey(state: PagingState<String, Item>): String? { return state.anchorPosition?.let { state.closestItemToPosition(it)?.id } }
}
| Parameters | |
|---|---|
| <Key : Any> | Type of key which define what data to load. E.g. Int to represent either a page number or item position, or String if your network uses Strings as next tokens returned with each response. |
| <Value : Any> | Type of data loaded in by this PagingSource. E.g., the type of data that will be passed to a androidx.paging.PagingDataAdapter to be displayed in a RecyclerView. |
Summary
Public constructors
PagingSource
<Key : Any, Value : Any> PagingSource()
| Parameters | |
|---|---|
| <Key : Any> | Type of key which define what data to load. E.g. Int to represent either a page number or item position, or String if your network uses Strings as next tokens returned with each response. |
| <Value : Any> | Type of data loaded in by this PagingSource. E.g., the type of data that will be passed to a androidx.paging.PagingDataAdapter to be displayed in a RecyclerView. |
Public functions
getRefreshKey
abstract fun getRefreshKey(state: PagingState<Key, Value>): Key?
Provide a [Key](/reference/kotlin/androidx/paging/PagingSource) used for the initial [load](/reference/kotlin/androidx/paging/PagingSource#load%28androidx.paging.PagingSource.LoadParams%29) for the next [PagingSource](/reference/kotlin/androidx/paging/PagingSource) due to invalidation of this [PagingSource](/reference/kotlin/androidx/paging/PagingSource). The [Key](/reference/kotlin/androidx/paging/PagingSource) is provided to [load](/reference/kotlin/androidx/paging/PagingSource#load%28androidx.paging.PagingSource.LoadParams%29) via [LoadParams.key](/reference/kotlin/androidx/paging/PagingSource.LoadParams#key%28%29).
The [Key](/reference/kotlin/androidx/paging/PagingSource) returned by this method should cause [load](/reference/kotlin/androidx/paging/PagingSource#load%28androidx.paging.PagingSource.LoadParams%29) to load enough items to fill the viewport around the last accessed position, allowing the next generation to transparently animate in. The last accessed position can be retrieved via [state.anchorPosition](/reference/kotlin/androidx/paging/PagingState#anchorPosition%28%29), which is typically the top-most or bottom-most item in the viewport due to access being triggered by binding items as they scroll into view.
For example, if items are loaded based on integer position keys, you can return ( (state.anchorPosition ?: 0) - state.config.initialLoadSize / 2).coerceAtLeast(0).
Alternately, if items contain a key used to load, get the key from the item in the page at index [state.anchorPosition](/reference/kotlin/androidx/paging/PagingState#anchorPosition%28%29) then try to center it based on state.config.initialLoadSize.
| Returns | |
|---|---|
| Key? | Key passed to load after invalidation used for initial load of the next generation. The Key returned by getRefreshKey should load pages centered around user's current viewport. If the correct Key cannot be determined, null can be returned to allow load decide what default key to use. |
invalidate
fun invalidate(): Unit
Signal the [PagingSource](/reference/kotlin/androidx/paging/PagingSource) to stop loading.
This method is idempotent. i.e., If [invalidate](/reference/kotlin/androidx/paging/PagingSource#invalidate%28%29) has already been called, subsequent calls to this method should have no effect.
unregisterInvalidatedCallback
fun unregisterInvalidatedCallback(onInvalidatedCallback: () -> Unit): Unit
Remove a previously added invalidate callback.
| Parameters | |
|---|---|
| onInvalidatedCallback: () -> Unit | The previously added callback. |