Paging 3 Quiz

ARCHITECTURE › Components

Why is cachedIn(viewModelScope) typically applied to a Pager's Flow<PagingData> in the ViewModel?

Answer: It caches loaded pages and shares them so data survives rotation

cachedIn() caches the loaded PagingData in the given scope and multicasts it, so rotation or repeated collection does not re-fetch; offline persistence is a RemoteMediator/DB concern, not cachedIn.

What does returning LoadResult.Page(data, prevKey = null, nextKey = null) from a PagingSource indicate?

Answer: There is nothing more to load in either direction

A null prevKey/nextKey tells Paging there is nothing more to load in that direction, so it stops prepending/appending; failures use LoadResult.Error and staleness uses LoadResult.Invalid.

In a network+database setup using RemoteMediator, what acts as the single source of truth for the UI?

Answer: The local database, which the PagingSource reads from

With a RemoteMediator the database is the single source of truth: the mediator writes network results into the DB and a DB-backed PagingSource (e.g. from Room) serves the UI, enabling offline support.

Which load direction's LoadState should drive a full-screen loading spinner or initial error screen?

Answer: refresh

loadState.refresh covers the initial load and manual refreshes, so it maps to the full-screen spinner/empty/error UI; append and prepend drive inline edge indicators while scrolling.

By default, what is PagingConfig.initialLoadSize relative to pageSize?

Answer: Three times pageSize

initialLoadSize defaults to pageSize * 3 so the first load fills more of the screen and reduces immediate follow-up loads; prefetchDistance defaults to pageSize.

In Jetpack Compose, how do you correctly provide stable item identity for a paged LazyColumn?

Answer: Pass items.itemKey { it.id } to the key parameter of items()

LazyPagingItems.itemKey { it.id } supplies stable keys that handle placeholders and shifting indices; raw indices are unstable because items shift as pages load, and collectAsState would not give a LazyPagingItems.

How should a user-triggered "Retry" button after a failed paged load be wired?

Answer: Call retry() on the LazyPagingItems or PagingDataAdapter

retry() re-attempts only the failed load(s) without resetting the list, whereas refresh() reloads everything; re-creating the Pager or re-collecting is unnecessary and loses paging state.

When Paging invalidates a PagingSource and builds a new one, how does getRefreshKey() keep the user near their current scroll position?

Answer: It derives a key from the closest loaded page's prevKey or nextKey

getRefreshKey() reads PagingState.anchorPosition (the most recently accessed index) and computes a key from the closest loaded page's prevKey/nextKey; the anchorPosition itself is an index, not a usable load key.

What does Paging do when a PagingSource's load() returns LoadResult.Invalid?

Answer: It drops the PagingSource and rebuilds it from the factory

LoadResult.Invalid signals the source is stale, so Paging throws away its results and invalidates it, prompting the Pager factory to instantiate a new PagingSource rather than retrying the old one.

For enablePlaceholders = true to actually render placeholders, what must the data source supply?

Answer: A known total item count so Paging can emit null for gaps

Placeholders require Paging to know the full item count up front (automatic with a Room-backed source); a custom PagingSource that does not report a count silently has placeholders disabled.

Where should PagingData operators like map and insertSeparators be applied in a ViewModel chain?

Answer: Before cachedIn(), so the transformed output is cached

PagingData transformations execute for every emission, so applying them before cachedIn() caches the transformed output; placing them after cachedIn() forces them to recompute for each new collector.

What causes Paging to call load() for an APPEND?

Answer: The user scrolling within prefetchDistance of the loaded edge

Paging automatically requests the next page once an accessed item comes within prefetchDistance of the loaded edge; there is no manual append() call, and load triggering is access-driven, not time-driven.

What is the purpose of overriding RemoteMediator.initialize()?

Answer: To return an InitializeAction that decides refresh vs. skip

initialize() returns LAUNCH_INITIAL_REFRESH or SKIP_INITIAL_REFRESH; skipping lets you serve still-fresh cached DB data immediately and avoid an unnecessary initial network refresh.

Which statement best describes a PagingData<T>?

Answer: A snapshot of paged data emitted as updates, not a persistent collection

PagingData is a self-contained snapshot of paged data emitted through a Flow; each emission is an update consumed via an adapter or collectAsLazyPagingItems, not a static indexable list.

Back to Paging 3