

Fetching data and binding it to the UI in the MAD skills series
source link: https://medium.com/androiddevelopers/fetching-data-and-binding-it-to-the-ui-in-the-mad-skills-series-cea89868b3e1
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Fetching data and binding it to the UI in the MAD skills series
Second episode in the Paging MAD skills series
Welcome back to the Paging 3.0 MAD Skills series! In the previous article, we went over the Paging library, saw how it fits into the app’s architecture, and we integrated it into the data layer of the app. We did this using a PagingSource
to fetch our data, and then used it, along with a PagingConfig
to create a Pager
object that provided a Flow<PagingData>
for UI consumption. In this article I’ll be covering how to actually consume the Flow<PagingData>
in your UI.
Preparing PagingData for the UI
The app currently has the ViewModel
exposing the information needed to render the UI in the UiState
data class, which contains a searchResult
field; an in-memory cache for result searches that survives configuration changes.
With Paging 3.0, we drop the searchResult
val from the UiState
, opting instead to replace it with a Flow
of PagingData<Repo>
exposed separately from the UiState
. This new Flow
will serve the same purpose as the searchResult
: provide a list of items to be rendered by the UI.
A private method “searchRepo()
” is added to the ViewModel
, which calls the Repository
to provide a PagingData
Flow
from the Pager
. We can then call this method to create our Flow<PagingData<Repo>>
based on the search terms the user enters. We also make use of the cachedIn
operator on the resulting PagingData
Flow
which caches it for quicker reuse using the ViewModelScope
.
It’s important to expose the PagingData
Flow
independent of other Flows
. This is because the PagingData
itself is a mutable type, and maintains its own internal stream of data that updates over time.
With the Flows
that comprise the fields of the UiState
fully defined, we can combine them into a StateFlow
of UiState
, which can then be exposed to, and consumed by the UI alongside the Flow
of PagingData
. With the above, we are now ready to start consuming our Flows
in the UI.
Consuming PagingData in the UI
The first thing we do is switch 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 changes in the backing data set are 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 submitData
suspending function.
Also, as a user experience 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 when we’ve finished loading and have presented data in the UI. We achieve this by taking advantage of the loadStateFlow
exposed by the PagingDataAdapter
and the “hasNotScrolledForCurrentSearch
’’ field in the UiState
used for tracking if the user has manually scrolled the list themselves. The combination of these two creates a flag to let us know if we can trigger an auto scroll.
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 load state flow notifies us we are not loading for each new query.
Adding Headers and Footers
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 implementation of a RecyclerView.Adapter
is automatically notified of changes in the Pager
as it loads data which enables it to insert items at the top or bottom of the list as needed.
The best part is you don’t even need to change your existing PagingDataAdapter
. The withLoadStateHeaderAndFooter
extension conveniently wraps your existing PagingDataAdapter
with both the header and footer!
The arguments of the withLoadStateHeaderAndFooter
function take definitions of LoadStateAdapters
for both the header and footer. The LoadStateAdapter’s
in turn host their own ViewHolders
, which are bound with the latest load state 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 I’ll cover more in the next article.
Next Up
With that we’ve bound our paging data to the UI! For a quick recap, we:
- Integrated our Paging in the UI layer using the PagingDataAdapter
- Used the LoadStateFlow exposed by the PagingDataAdapter to guarantee we only auto scroll to the top of the list when the Pager is done loading
- Used the withLoadStateHeaderAndFooter() to add progress bars to UI when fetching data
Thanks for reading along! 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
!
Recommend
-
18
Previous post Suspense is and will become a game changer when it comes to data f...
-
31
-
13
January 20, 2019 Data fetching in React the functional way powered by TypeScript, io-ts & fp-ts
-
9
Understanding the effective data fetching with JPA Entity Graphs (Part-2) JPA • Sep 18, 2020
-
12
Data Fetching on the Web Still SucksIt’s 2021, and data fetching on the web still sucks. This is crazy! If you’re building a web app at...
-
10
-
6
#Featured #Latest #PagingPaging: Fetching data...
-
13
BackFetching and Updating Data with React QueryJune 16th, 2022 · 4 min read
-
2
Pre-Rendering and Data Fetching Strategies in Next.js
-
3
Simple and small two-way data binding between DOM and data · GitHub Instantly share code, notes, and snippets.
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK