PagingSource

public abstract class PagingSource<Key extends Object, Value extends Object>

Known direct subclasses
ListenableFuturePagingSource

ListenableFuture-based compatibility wrapper around PagingSource's suspending APIs.

RxPagingSource

Rx-based compatibility wrapper around PagingSource's suspending APIs.

RxPagingSource

Rx-based compatibility wrapper around PagingSource's suspending APIs.


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 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)
        }
    }
}
/**
 * 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. 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 extends Object>

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
Pager

Summary

Nested types

PagingSource.LoadParams

Params for a load request on a PagingSource from PagingSource.load.

PagingSource.LoadParams.Append

Params to load a page of data from a PagingSource via PagingSource.load to be appended to the end of the list.

PagingSource.LoadParams.Prepend

Params to load a page of data from a PagingSource via PagingSource.load to be prepended to the start of the list.

PagingSource.LoadParams.Refresh

Params for an initial load request on a PagingSource from PagingSource.load or a refresh triggered by invalidate.

PagingSource.LoadResult

Result of a load request from PagingSource.load.

PagingSource.LoadResult.Error

Error result object for PagingSource.load.

PagingSource.LoadResult.Invalid

Invalid result object for PagingSource.load

PagingSource.LoadResult.Page

Success result object for PagingSource.load.

PagingSource.LoadResult.Page.Companion

Public fields

final boolean

Whether this PagingSource has been invalidated, which should happen when the data this PagingSource represents changes since it was first instantiated.

boolean

true if this PagingSource supports jumping, false otherwise.

boolean

true if this PagingSource expects to re-use keys to load distinct pages without a call to invalidate, false otherwise.

Public constructors

<Key extends Object, Value extends Object> PagingSource()

Public methods

abstract @Nullable Key

Provide a Key used for the initial load for the next PagingSource due to invalidation of this PagingSource.

final void

Signal the PagingSource to stop loading.

abstract @NonNull PagingSource.LoadResult<@NonNull Key, @NonNull Va