PagingSource
abstract class PagingSource<Key : Any, Value : Any>
kotlin.Any | |
↳ | androidx.paging.PagingSource |
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 PagingSources might be from network or from a database.
An instance of a PagingSource is used to load pages of data for an instance of PagingData.
A 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 / PagingData pair must be created to represent an updated snapshot of the data.
Loading Pages
PagingData queries data from its PagingSource in response to loading hints generated as
the user scrolls in a RecyclerView
.
To control how and when a PagingData queries data from its PagingSource, see PagingConfig, which defines behavior such as PagingConfig.pageSize and PagingConfig.prefetchDistance.
Updating Data
A PagingSource / PagingData pair is a snapshot of the data set. A new PagingData / PagingData must be created if an update occurs, such as a reorder, insert, delete, or content update occurs. A PagingSource must detect that it cannot continue loading its snapshot (for instance, when Database query notices a table being invalidated), and call invalidate. Then a new PagingSource / 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 to a RecyclerView
, create an instance of Pager,
which provides a stream of PagingData that you may collect from and submit to a
PagingDataAdapter.
/** * Sample Page-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<String>): 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) } } }
/** * Sample Page-Indexed 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<Int>): 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) } } }
Summary
Nested classes | |
---|---|
sealed |
Params for a load request on a PagingSource from PagingSource.load. |
sealed |
Result of a load request from PagingSource.load. |
Public constructors | |
---|---|
<init>() Base class for an abstraction of pageable static data from some source, where loading pages of data is typically an expensive operation. |
Public methods | |
---|---|
open Key? |
getRefreshKey(state: PagingState<Key, Value>) Request a refresh key given the current PagingState of the associated PagingData used to present loaded data from this PagingSource. |
Unit |
Signal the PagingSource to stop loading. |
abstract suspend PagingSource.LoadResult<Key, Value> |
load(params: PagingSource.LoadParams<Key>) Loading API for PagingSource. |
Unit |
registerInvalidatedCallback(onInvalidatedCallback: () -> Unit) Add a callback to invoke when the PagingSource is first invalidated. |
Unit |
unregisterInvalidatedCallback(onInvalidatedCallback: () -> Unit) Remove a previously added invalidate callback. |
Properties | |
---|---|
Boolean |
Whether this PagingSource has been invalidated, which should happen when the data this PagingSource represents changes since it was first instantiated. |
open Boolean |
|
open Boolean |
|
Public constructors
<init>
PagingSource()
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 PagingSources might be from network or from a database.
An instance of a PagingSource is used to load pages of data for an instance of PagingData.
A 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 / PagingData pair must be created to represent an updated snapshot of the data.
Loading Pages
PagingData queries data from its PagingSource in response to loading hints generated as
the user scrolls in a RecyclerView
.
To control how and when a PagingData queries data from its PagingSource, see PagingConfig, which defines behavior such as PagingConfig.pageSize and PagingConfig.prefetchDistance.
Updating Data
A PagingSource / PagingData pair is a snapshot of the data set. A new PagingData / PagingData must be created if an update occurs, such as a reorder, insert, delete, or content update occurs. A PagingSource must detect that it cannot continue loading its snapshot (for instance, when Database query notices a table being invalidated), and call invalidate. Then a new PagingSource / 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 to a RecyclerView
, create an instance of Pager,
which provides a stream of PagingData that you may collect from and submit to a
PagingDataAdapter.
/** * Sample Page-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<String>): 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) } } }
/** * Sample Page-Indexed 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<Int>): 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) } } }
Parameters | |
---|---|
Key |
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 |
Type of data loaded in by this PagingSource. E.g., the type of data that will be
passed to a PagingDataAdapter to be displayed in a
RecyclerView . |
See Also
Public methods
getRefreshKey
open fun getRefreshKey(state: PagingState<Key, Value>): Key?
Request a refresh key given the current PagingState of the associated PagingData used to present loaded data from this PagingSource.
The Key returned by this method is used to populate the LoadParams.key for load requests of type REFRESH.
For example, if items are loaded based on position, and keys are positions, getRefreshKey should return the position of the item.
Alternately, if items contain a key used to load, get the key from the item in the page at index PagingState.anchorPosition.
If this operation cannot be supported (generally, because keys cannot be reused across
refresh) return null
- this is the default behavior.
Note: This method is guaranteed to only be called if the initial load succeeds and the list of loaded pages is not empty. In the case where a refresh is triggered before the initial load succeeds or it errors out, the initial key passed to Pager will be used.
invalidate
fun invalidate(): Unit
Signal the PagingSource to stop loading.
This method is idempotent. i.e., If invalidate has already been called, subsequent calls to this method should have no effect.
load
abstract suspend fun load(params: PagingSource.LoadParams<Key>): PagingSource.LoadResult<Key, Value>
Loading API for PagingSource.
Implement this method to trigger your async load (e.g. from database or network).
registerInvalidatedCallback
fun registerInvalidatedCallback(onInvalidatedCallback: () -> Unit): Unit
Add a callback to invoke when the PagingSource is first invalidated.
Once invalidated, a PagingSource will not become valid again.
A PagingSource will only invoke its callbacks once - the first time invalidate is called, on that thread.
Parameters | |
---|---|
onInvalidatedCallback: () -> Unit | The callback that will be invoked on thread that invalidates the PagingSource. |
unregisterInvalidatedCallback
fun unregisterInvalidatedCallback(onInvalidatedCallback: () -> Unit): Unit
Remove a previously added invalidate callback.
Parameters | |
---|---|
onInvalidatedCallback: () -> Unit | The previously added callback. |
Properties
invalid
val invalid: Boolean
Whether this PagingSource has been invalidated, which should happen when the data this PagingSource represents changes since it was first instantiated.
jumpingSupported
open val jumpingSupported: Boolean
true
if this PagingSource supports jumping, false
otherwise.
Override this to true
if pseudo-fast scrolling via jumps is supported.
A jump occurs when a RecyclerView
scrolls through a number of placeholders defined by
PagingConfig.jumpThreshold and triggers a load with LoadType.
PagingSources that support jumps should override getRefreshKey to return a Key that would load data fulfilling the viewport given a user's current PagingState.anchorPosition.
See Also
keyReuseSupported
open val keyReuseSupported: Boolean
true
if this PagingSource expects to re-use keys to load distinct pages
without a call to invalidate, false
otherwise.