@MainThread public abstract class PagedList.BoundaryCallback<T extends Object>

Signals when a PagedList has reached the end of available data.

When local storage is a cache of network data, it's common to set up a streaming pipeline: Network data is paged into the database, database is paged into UI. Paging from the database to UI can be done with a LiveData<PagedList>, but it's still necessary to know when to trigger network loads.

BoundaryCallback does this signaling - when a PagingSource runs out of data at the end of the list, onItemAtEndLoaded is called, and you can start an async network load that will write the result directly to the database. Because the database is being observed, the UI bound to the LiveData<PagedList> will update automatically to account for the new items.

Note that a BoundaryCallback instance shared across multiple PagedLists (e.g. when passed to androidx.paging.LivePagedListBuilder.setBoundaryCallback, the callbacks may be issued multiple times. If for example onItemAtEndLoaded triggers a network load, it should avoid triggering it again while the load is ongoing.

The database + network Repository in the PagingWithNetworkSample shows how to implement a network BoundaryCallback using Retrofit, while handling swipe-to-refresh, network errors, and retry.

Requesting Network Data

BoundaryCallback only passes the item at front or end of the list when out of data. This makes it an easy fit for item-keyed network requests, where you can use the item passed to the BoundaryCallback to request more data from the network. In these cases, the source of truth for next page to load is coming from local storage, based on what's already loaded.

If you aren't using an item-keyed network API, you may be using page-keyed, or page-indexed. If this is the case, the paging library doesn't know about the page key or index used in the BoundaryCallback, so you need to track it yourself. You can do this in one of two ways:

Local storage Page key
If you want to perfectly resume your query, even if the app is killed and resumed, you can store the key on disk. Note that with a positional/page index network API, there's a simple way to do this, by using the listSize as an input to the next load (or listSize / NETWORK_PAGE_SIZE, for page indexing).

The current list size isn't passed to the BoundaryCallback though. This is because the PagedList doesn't necessarily know the number of items in local storage. Placeholders may be disabled, or the PagingSource may not count total number of items.

Instead, for these positional cases, you can query the database for the number of items, and pass that to the network.

In-Memory Page key
Often it doesn't make sense to query the next page from network if the last page you fetched was loaded many hours or days before. If you keep the key in memory, you can refresh any time you start paging from a network source.

Store the next key in memory, inside your BoundaryCallback. When you create a new BoundaryCallback when creating a new LiveData/Observable of PagedList, refresh data. For example, in the Paging Codelab, the GitHub network page index is stored in memory.

<T extends Object>

Type loaded by the PagedList.


Public constructors

<T extends Object> BoundaryCallback()

Public methods

onItemAtEndLoaded(T itemAtEnd)

Called when the item at the end of the PagedList has been loaded, and access has occurred within PagedList.Config.prefetchDistance of it.

onItemAtFrontLoaded(T itemAtFront)

Called when the item at the front of the PagedList has been loaded, and access has occurred within PagedList.Config.prefetchDistance of it.


Called when zero items are returned from an initial load of the PagedList's data source.

Public constructors


public final <T extends Object>