PagingDataAdapter

public abstract class PagingDataAdapter<T extends Object, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter


RecyclerView.Adapter base class for presenting paged data from PagingDatas in a RecyclerView.

This class is a convenience wrapper around AsyncPagingDataDiffer that implements common default behavior for item counting, and listening to update events.

To present a Pager, use collectLatest to observe Pager.flow and call submitData whenever a new PagingData is emitted.

If using RxJava and LiveData extensions on Pager, use the non-suspending overload of submitData, which accepts a Lifecycle.

PagingDataAdapter listens to internal PagingData loading events as pages are loaded, and uses DiffUtil on a background thread to compute fine grained updates as updated content in the form of new PagingData objects are received.

State Restoration: To be able to restore RecyclerView state (e.g. scroll position) after a configuration change / application recreate, PagingDataAdapter calls RecyclerView.Adapter.setStateRestorationPolicy with RecyclerView.Adapter.StateRestorationPolicy.PREVENT upon initialization and waits for the first page to load before allowing state restoration. Any other call to RecyclerView.Adapter.setStateRestorationPolicy by the application will disable this logic and will rely on the user set value.

val USER_COMPARATOR = object : DiffUtil.ItemCallback<User>() {
    override fun areItemsTheSame(oldItem: User, newItem: User): Boolean =
        // User ID serves as unique ID
        oldItem.userId == newItem.userId

    override fun areContentsTheSame(oldItem: User, newItem: User): Boolean =
        // Compare full contents (note: Java users should call .equals())
        oldItem == newItem
}

class UserAdapter : PagingDataAdapter<User, UserViewHolder>(USER_COMPARATOR) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        return UserViewHolder.create(parent)
    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        val repoItem = getItem(position)
        // Note that item may be null, ViewHolder must support binding null item as placeholder
        holder.bind(repoItem)
    }
}

Summary

Public fields

final @NonNull Flow<@NonNull CombinedLoadStates>

A hot Flow of CombinedLoadStates that emits a snapshot whenever the loading state of the current PagingData changes.

final @NonNull Flow<Unit>

A hot Flow that emits after the pages presented to the UI are updated, even if the actual items presented don't change.

Public constructors

<T extends Object, VH extends RecyclerView.ViewHolder> PagingDataAdapter(
    @NonNull DiffUtil.ItemCallback<@NonNull T> diffCallback,
    @NonNull CoroutineDispatcher mainDispatcher,
    @NonNull CoroutineDispatcher workerDispatcher
)

Public methods

final void
addLoadStateListener(
    @NonNull Function1<@NonNull CombinedLoadStatesUnit> listener
)

Add a CombinedLoadStates listener to observe the loading state of the current PagingData.

final void
addOnPagesUpdatedListener(@NonNull Function0<Unit> listener)

Add a listener which triggers after the pages presented to the UI are updated, even if the actual items presented don't change.

int

Returns the total number of items in the data set held by the adapter.

final long
getItemId(int position)

Note: getItemId is final, because stable IDs are unnecessary and therefore unsupported.

final @Nullable T
peek(@IntRange(from = 0) int index)

Returns the presented item at the specified position, without notifying Paging of the item access that would normally trigger page loads.

final void

Refresh the data presented by this PagingDataAdapter.

final void

Remove a previously registered CombinedLoadStates listener.

final void

Remove a previously registered listener for new PagingData generations completing initial load and presenting to the UI.

final void

Retry any failed load requests that would result in a LoadState.Error update to this PagingDataAdapter.

final void
setHasStableIds(boolean hasStableIds)

Stable ids are unsupported by PagingDataAdapter.

void

Sets the state restoration strategy for the Adapter.

final @NonNull ItemSnapshotList<@NonNull T>

Returns a new ItemSnapshotList representing the currently presented items, including any placeholders if they are enabled.

final void

Present a PagingData until it is invalidated by a call to refresh or PagingSource.invalidate.

final void
submitData(
    @NonNull Lifecycle lifecycle,
    @NonNull PagingData<@NonNull T> pagingData
)

Present a PagingData until it is either invalidated or another call to submitData is made.

final @NonNull ConcatAdapter

Create a ConcatAdapter with the provided LoadStateAdapters displaying the LoadType.APPEND as a list item at the start of the presented list.

final @NonNull ConcatAdapter

Create a ConcatAdapter with the provided LoadStateAdapters displaying the LoadType.PREPEND as a list item at the end of the presented list.

final @NonNull ConcatAdapter

Create a ConcatAdapter with the provided LoadStateAdapters displaying the LoadType.PREPEND and LoadType.APPENDs as list items at the start and end respectively.

Inherited methods

From class RecyclerView.Adapter
final void
bindViewHolder(@NonNull VH holder, int position)
boolean
final @NonNull VH
createViewHolder(@NonNull ViewGroup parent, int viewType)
int
int
getItemViewType(int position)
final @NonNull RecyclerView.Adapter.StateRestorationPolicy
final boolean
final boolean
final void
final void
notifyItemChanged(int position)
final void
notifyItemChanged(int position, @Nullable Object payload)
final void
notifyItemInserted(int position)
final void
notifyItemMoved(int fromPosition, int toPosition)
final void
notifyItemRangeChanged(int positionStart, int itemCount)
final void
notifyItemRangeChanged(
    int positionStart,
    int itemCount,
    @Nullable Object payload
)
final void
notifyItemRangeInserted(int positionStart, int itemCount)
final void
notifyItemRangeRemoved(int positionStart, int itemCount)
final void
notifyItemRemoved(int position)
void
abstract void
onBindViewHolder(@NonNull VH holder, int position)
void
onBindViewHolder(
    @NonNull VH holder,
    int position,
    @NonNull List<@NonNull Object> payloads
)
abstract @NonNull VH
onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
void
boolean
void
void
void
onViewRecycled(@NonNull VH holder)
void
void

Public fields

loadStateFlow

@NonNull
public final @NonNull Flow<@NonNull CombinedLoadStatesloadStateFlow

A hot Flow of CombinedLoadStates that emits a snapshot whenever the loading state of the current PagingData changes.

This flow is conflated, so it buffers the last update to CombinedLoadStates and immediately delivers the current load states on collection.

onPagesUpdatedFlow

@NonNull
public final @NonNull Flow<UnitonPagesUpdatedFlow

A hot Flow that emits after the pages presented to the UI are updated, even if the actual items presented don't change.

An update is triggered from one of the following:

  • submitData is called and initial load completes, regardless of any differences in the loaded data

  • A Page is inserted

  • A Page is dropped

Note: This is a SharedFlow configured to replay 0 items with a buffer of size 64. If a collector lags behind page updates, it may trigger multiple times for each intermediate update that was presented while your collector was still working. To avoid this behavior, you can conflate this Flow so that you only receive the latest update, which is useful in cases where you are simply updating UI and don't care about tracking the exact number of page updates.

Public constructors

PagingDataAdapter

public final <T extends Object, VH extends RecyclerView.ViewHolder> PagingDataAdapter(
    @NonNull DiffUtil.ItemCallback<@NonNull T> diffCallback,
    @NonNull CoroutineDispatcher mainDispatcher,
    @NonNull CoroutineDispatcher workerDispatcher
)

Public methods

addLoadStateListener

@NonNull
public final void addLoadStateListener(
    @NonNull Function1<@NonNull CombinedLoadStatesUnit> listener
)

Add a CombinedLoadStates listener to observe the loading state of the current PagingData.

As new PagingData generations are submitted and displayed, the listener will be notified to reflect the current CombinedLoadStates.

val adapter = UserPagingAdapter()
adapter.addLoadStateListener {
    // show a retry button outside the list when refresh hits an error
    retryButton.isVisible = it.refresh is LoadState.Error

    // swipeRefreshLayout displays whether refresh is occurring
    swipeRefreshLayout.isRefreshing = it.refresh is LoadState.Loading

    // show an empty state over the list when loading initially, before items are loaded
    emptyState.isVisible = it.refresh is LoadState.Loading && adapter.itemCount == 0
}
Parameters
@NonNull Function1<@NonNull CombinedLoadStatesUnit> listener

LoadStates listener to receive updates.

addOnPagesUpdatedListener

@NonNull
public final void addOnPagesUpdatedLis