[MUSIC PLAYING]
TJ DAHUNSI: Welcome back.
In the last episode, we went over the Paging library
and how it fits into the app's architecture,
and integrated it into the data layer of the app.
We did this using a paging source to fetch the data,
and then used it along with the paging config
to create a pager object.
In this video, we're going to start using the pager
to start populating the UI.
Let's get started.
Recall that a pager exposes a stream of paging data,
the class responsible for providing
a window into the back end data set
and publishing updates to it.
The app currently has a view model
exposing the information needed to render the UI in the UiState
data class, in which we expose the search results,
and in memory cache for results, searches that
survives configuration changes.
With Paging 3.0, we drop the search result val
from the UiState, opting instead to replace it
with the flow of PagingData Repo, exposed separately
from the UiState.
This new flow will serve the same purpose as the search
result. That is, it provides the list of items
to be rendered by the UI.
We update the view model to have a private method, searchRepo,
which calls on the repository to provide a PagingData
Flow from the pager we created in the last video.
We can then call on this method to create a PagingData
Flow based on the search items the user enters.
We also make use of the cachedIn operator
on the PagingData Flow, which caches it
for quicker re-use using the viewModelScope.
It's important to expose the PagingData Flow
independent of other flows.
This is because the PagingData itself updates and maintains
its own internal stream of data over time.
With the flows that comprise the fields of the UiState fully
defined, we can combine them into a state flow of UiState,
which can then be exposed to and consumed by the UI
alongside the flow of the PagingData.
We are now ready to start consuming a flow
with PagingData in the UI.
The first thing we do is switch to the RecyclerView adapter
from a ListAdapter to a PagingDataAdapter.
A PagingDataAdapter is a RecyclerView adapter
optimized for diffing and aggregating updates
from PagingData to make sure our changes in the backing data set
have propagated as efficiently as possible.
Next, we start to collect from the PagingData Flow
so we can bind its emissions to the PagingDataAdapter using
the Submit Data Suspending Function.
Also, as a user-experienced perk,
we want to make sure that when the user searches for something
new, they are taken to the top of the list
to show the first search results.
We want to do this when we're confident that we
aren't loading anymore data.
We do this by taking advantage of the loadStateFlow exposed
by the PagingDataAdapter and the hasNotScrolledFo
rCurrentSearchField in the UiState.
The combination of these two creates
the flags to let us know if we can trigger an autoscroll.
Since the load states provided by the loadStateFlow
are synchronous with what is displayed in the UI,
we can confidently scroll to the top of the list
once the loadStateFlow notifies us we are not
loading for each new query.
Another advantage of the Paging library
is the ability to display progress indicators
either at the top or bottom of the list with the help
of the LoadStateAdapter.
This is an implementation of RecyclerView Adapter that
is automatically notified of changes in pagers
as it loads data, which enables it to insert an item to the end
or to the top of the list as needed.
The best part is, you don't even need to change your existing
PagingDataAdapter.
The withLoadStateHeaderAndFooter extension conveniently
wraps the existing pager adapter with both the header
and the footer.
The argument of the withLoadStateHeaderAndFooter
function take definitions of LoadState adapters for both
the header and the footer.
The LoadState adapters, in turn, host their own view
holders, which are bound with the latest LoadState,
making it easy to define the behavior of the views.
We can even pass arguments to let us retry loading in case
there's an error, which you'll see in the next episode.
With that, we've bound our paging data to the UI.
For a quick recap, we integrated the paging data in the UI layer
using the PagingDataAdapter, used the loadStateFlow exposed
by the PagingDataAdapter to guarantee
we only autoscrolled to the top of the list
when the pager is done loading.
We've also used the withLoadStateHeaderAndFooter
to add progress bars to the UI when fetching data.
That's it for this episode.
Stay tuned, and see you in the next one,
where we'll be looking at paging from the database as a single
source of truth , and taking a closer look
at the loadStateFlow.
See ya.
[MUSIC PLAYING]