PagingSource
public abstract class PagingSource<Key extends Object, Value extends Object>
ListenableFuturePagingSource |
|
RxPagingSource |
Rx-based compatibility wrapper around |
RxPagingSource |
Rx-based compatibility wrapper around |
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 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<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) } } 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<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) } } override fun getRefreshKey(state: PagingState<String, Item>): String? { return state.anchorPosition?.let { state.closestItemToPosition(it)?.id } } }
| Parameters | |
|---|---|
<Key extends Object> |
Type of key which define what data to load. E.g. |
<Value extends Object> |
Type of data loaded in by this |
| See also | |
|---|---|
Pager |
Summary
Nested types |
|---|
public sealed class PagingSource.LoadParams<Key extends Object>Params for a load request on a |
public final class PagingSource.LoadParams.Append<Key extends Object> extends PagingSource.LoadParamsParams to load a page of data from a |
public final class PagingSource.LoadParams.Prepend<Key extends Object> extends PagingSource.LoadParamsParams to load a page of data from a |
public final class PagingSource.LoadParams.Refresh<Key extends Object> extends PagingSource.LoadParamsParams for an initial load request on a |
public sealed class PagingSource.LoadResult<Key extends Object, Value extends Object>Result of a load request from |
public final class PagingSource.LoadResult.Error<Key extends Object, Value extends Object> extends PagingSource.LoadResultError result object for |
public final class PagingSource.LoadResult.Invalid<Key extends Object, Value extends Object> extends PagingSource.LoadResultInvalid result object for |
public final class PagingSource.LoadResult.Page<Key extends Object, Value extends Object> extends PagingSource.LoadResult implements IterableSuccess result object for |
Public constructors |
|---|
<Key extends Object, Value extends Object> PagingSource() |
Public methods |
|
|---|---|
final boolean |
Whether this |
boolean |
|
boolean |
|
abstract Key |
getRefreshKey(@NonNull PagingState<@NonNull Key, @NonNull Value> state)Provide a |
final void |
Signal the |
abstract @NonNull PagingSource.LoadResult<@NonNull Key, @NonNull Value> |
load(@NonNull PagingSource.LoadParams<@NonNull Key> params)Loading API for |
final void |
registerInvalidatedCallback(Add a callback to invoke when the |
final void |
unregisterInvalidatedCallback(Remove a previously added invalidate callback. |
Public constructors
PagingSource
public <Key extends Object, Value extends Object> PagingSource()
| Parameters | |
|---|---|
<Key extends Object> |
Type of key which define what data to load. E.g. |
<Value extends Object> |
Type of data loaded in by this |
Public methods
getInvalid
public final boolean getInvalid()
Whether this PagingSource has been invalidated, which should happen when the data this PagingSource represents changes since it was first instantiated.
getJumpingSupported
public boolean getJumpingSupported()
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.
To support jumping, the LoadResult.Page returned from this PagingSource must implement itemsBefore and itemsAfter to notify Paging the boundaries within which it can jump.
| See also | |
|---|---|
jumpThreshold |
getKeyReuseSupported
public boolean getKeyReuseSupported()
true if this PagingSource expects to re-use keys to load distinct pages without a call to invalidate, false otherwise.
getRefreshKey
public abstract Key getRefreshKey(@NonNull PagingState<@NonNull Key, @NonNull Value> state)
Provide a Key used for the initial load for the next PagingSource due to invalidation of this PagingSource. The Key is provided to load via LoadParams.key.
The Key returned by this method should cause load 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, 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 then try to center it based on state.config.initialLoadSize.
| Parameters | |
|---|---|
@NonNull PagingState<@NonNull Key, @NonNull Value> state |
|
invalidate
public final void invalidate()
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
public abstract @NonNull PagingSource.LoadResult<@NonNull Key, @NonNull Value> load(@NonNull PagingSource.LoadParams<@NonNull Key> params)
Loading API for PagingSource.
Implement this method to trigger your async load (e.g. from database or network).
registerInvalidatedCallback
public final void registerInvalidatedCallback(
@NonNull Function0<Unit> onInvalidatedCallback
)
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.
If this PagingSource is already invalid, the provided onInvalidatedCallback will be triggered immediately.
| Parameters | |
|---|---|
@NonNull Function0<Unit> onInvalidatedCallback |
The callback that will be invoked on thread that invalidates the |