Android by example: Google’s recent Android paging Library — Pokedex
Google recently announced the paging library, which is quite an interesting take on implementing paging functionality. In this article I try to explain different components needed to implement the paging library, the role of each one and how they interact.
The chunks of code presented in this article are from this project. This is what it looks like.
I break down this article to 3 parts: The data, the UI and the business code -where the magic happens-.
The data part of the app is based on Android’s architecture component Room. It is composed of 2 main parts:
- The entity, Dao and Database
- The database populator
The entity class represents a Pokemon, which is characterized by an id and a name. The only noticeable thing about it is the fact that it contains an implementation of DiffCallback.
DiffCallback is used to efficiently update the items inside a list with the DiffUtils class. Using it means implementing 2 methods: areItemsTheSame and areContentsTheSame (the method names are self-explanatory).
The data access object defines the methods that access the database (whether for reading or writing). In this example there are both, a method for reading all the data, and one for -bulk- inserting.
Since Room is being used in this example to manage the database, the DAO object can generate a *LivePagedListProvider from the query, using *TiledDataSource, which will use the Integer parameter when deciding which item to load.
The database class is pretty straightforward, nothing special to mention about it.
Uses an array of pokemon names stored as strings in the project (in arrays.xml) and populates the database. This is done only once (or whenever the app detects that the database is empty).
The UI is pretty simple and straight-forward, so I’ll keep it brief. It’s composed of two layouts:
- The activity layout: Contains uniquely a RecyclerView
- The list item layout: CardView that contains the id, sprite (image) and name of the pokemon.
The real deal
Extends the RecyclerView.ViewHolder class, basically binds the item view elements to their values: Pokemon id, name and sprite (image).
Extends PagedListAdapter<T, VH> where:
- T: Class that we’re binding to each item view (in this example, Pokemon.java)
- VH: ViewHolder class
The thing worth noting about this class is its constructor, remember when in the entity class, we defined a DiffCallback instance? In our adapter’s constrauctor, we call the parent’s constructor (PagedListAdapter) with the entity’s DiffCallback, which is used to compare items in the list.
Extends Android architect component’s ViewModel. This class is responsible for instanciating the LiveData for our PagedList while defining settings such as the page size (20 elements) and prefetch data (5).
the main thing to notice about the activity is that it synchronizes the LiveData from the ViewModel and the Adapter’s data: Whenever a modification happens on the LiveData, the adapter is notified in order to react accordingly.
This article is only a simple implementation of the paging library alongside a couple of Android’s architecture components, the library offers other possibilites not addressed here, and much more is yet to come given the fact that it is still in its early days.
Notions worth explaining
PagedList: Component that loads data from a *DataSource (the loading is done on a background thread, but consumed on the main thread). It has several configurable parameters such as the page size, the prefetch distance and the initial load size.
LivePagedListProvider: Component that provides a LiveData<PagedList> from a provided Data source.
DataSource: Base class for data loading, used in list paging. It provides data gradually, using it requires implementing one of its subclasses: TilesDataSource and KeyedDataSource.
TiledDataSource: Data loader used to load data from arbitrary positions in a list based solely on position information, provides a fixed number of items.
KeyedDataSource: Data loader used to load keyed content (loading element N requires data from element N-1). An example of this would be loading the next video in a playlist, you’d need the id of the previous video.