Paging Library for Android With Kotlin: Creating Infinite Lists
In this tutorial, you’ll build a simple Reddit clone that loads pages of information gradually into an infinite list using Paging 3.0 and Room. By Harun Wangereka.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Paging Library for Android With Kotlin: Creating Infinite Lists
30 mins
- Getting Started
- Defining a PagingSource
- Fetching Reddit Posts From the Network
- Fetching Posts From the PagingSource
- Configuring Your ViewModel to Fetch Data
- Using a PagingData Adapter
- Displaying Data in Your UI
- Enabling Key Reuse
- Displaying the Loading State
- Breaking Free of Network Dependency
- Creating a RemoteMediator
- Adding RemoteMediator to Your Repository
- Fetching Previous and Next Pages With RemoteMediator
- Paging 3.0 Remarks
- Where to Go From Here?
Lists are an essential part of mobile development. A list is a great option when you have a lot of information to display, and it contains items of similar type.
Some lists don’t have a fixed size. There’s often too much information to display all at once. For example, think about your Facebook feed. If Facebook loaded and displayed every post, image or Like every time you opened it, the list would never finish loading.
Instead, Facebook uses infinitely loading lists, as do most apps with large datasets. In an infinitely loading list, you download only as much data as the user will immediately consume. Then you load more data as the user scrolls farther in the list.
Implementing infinitely loading lists is an arduous process. To make it easier, Google provides a Paging library. It includes several core classes to help you create progressively loading lists. These classes abstract the logic that determines when to load new items. The Paging library also provides tie-ins to other core architecture components. These include the LiveData streaming library and the Room storage library.
In this tutorial, you’ll build a simple Reddit clone. It uses the Android Paging library to load information into an infinite list, page by page. During this process you’ll learn several important skills:
- Implement the Paging 3.0 library.
- Add headers and footers in infinitely loading lists.
- Learn how to use Room with the Paging Library.
Now it’s time to get to work!
Getting Started
Start by downloading the materials for this tutorial using the Download Materials button at the top or bottom of this tutorial. Fire up Android Studio 4 or later, and import the starter project.
You’ll see that there’s a networking package with several model classes. It also contains a RedditService
class that provides the Reddit API.The project also includes several empty classes that you’ll flesh out as you work through the tutorial.
Now, build and run. You’ll see an empty screen.
To begin populating the screen, you’ll use the Reddit API which returns pages of Reddit posts.
Defining a PagingSource
Your first task is to create a PagingSource
that will pull down Reddit information. A PagingSource is a class that manages the loading of data in small sets/pages for your list. In the data from the Reddit API, you receive a list of Reddit posts corresponding to a single page via the dist
key, which is known as the a one-page key.
Head over to repositories/RedditPagingSource.kt:
class RedditPagingSource(private val redditService: RedditService) :
// 1 & 2
PagingSource<String, RedditPost>() {
override suspend fun load(params: LoadParams<String>):
LoadResult<String, RedditPost> {
TODO("not implemented")
}
}
As you can see above, PagingSource
has two parameters:
-
String
: Reddit API providesbefore
andafter
keys, which tell the API how it is going to fetch the previous and next pages of data. -
RedditPost
: The information received from the Reddit API i.e a list of Reddit posts of typeRedditPost
.
At the same time, notice that the load
method is not yet implemented. It accepts LoadParams
as an argument, which is a sealed Kotlin class that keeps information related to the load operation. It does so via its below class properties:
- loadSize: Number of items you’re requesting.
- placeholdersEnabled: Boolean value that indicates whether or not you’re using a placeholder.
In the next section, you’ll add the logic to fetch data from the Reddit API.
Fetching Reddit Posts From the Network
While still inside repositories/RedditPagingSource.kt, replace the TODO()
with the following code:
return try {
// 1
val response = redditService.fetchPosts(loadSize = params.loadSize)
// 2
val listing = response.body()?.data
val redditPosts = listing?.children?.map { it.data }
// 3
LoadResult.Page(
// 4
redditPosts ?: listOf(),
// 5
listing?.before,
listing?.after
)
} catch (exception: IOException) { // 6
return LoadResult.Error(exception)
} catch (exception: HttpException) {
return LoadResult.Error(exception)
}
Here’s what is happening here:
-
RedditService
is used to fetch the list of posts from the Reddit API, passing loadSize as a parameter, viaLoadParams
. - Get the list of posts from the body of the response.
- Create an instance of
LoadResult.Page
by providing all arguments. - Pass in the list of reddit posts. If the case when API call didn’t return any RedditPosts, you pass an empty list.
- Pass in the
before
andafter
keys you received in the response body from the Reddit API. - Finally, two catch blocks handle exceptions and return
LoadResult.Error
.
The code block above returns LoadResult
, which is another sealed class that can take the following forms:
- When the network call executes successfully,
load()
returnsLoadResult.Page
. - If an error occurred when executing the network call,
load()
returnsLoadResult.Error
.
When the IDE prompts you, make sure you add the imports to resolve the errors.
Next, you’ll use this RedditPagingSource
to get list of posts.
Fetching Posts From the PagingSource
An advantage of the Paging 3.0 library is that its components conform to the Model-View-ViewModel (MVVM) architecture. RedditPagingSource
acts as a data source, corresponding to the Model layer in the MVVM.
Navigate to repositories/RedditRepo.kt. Add the following code block to the class:
// 1
private val redditService = RedditClient.getClient().create(RedditService::class.java)
// 2
fun fetchPosts(): Flow<PagingData<RedditPost>> {
// 3
return Pager(
PagingConfig(pageSize = 40, enablePlaceholders = false)
) {
RedditPagingSource(redditService)
}.flow
}
Here,
- You create a reference to
RedditService
to download list of posts from the Reddit API - You return an instance of
Pager
class, which is used to fetch a stream of data fromPagingSource
. The Paging library supports several return types. These includeFlow
,LiveData
, and the RxJavaFlowable
andObservable
. In this tutorial, you’ll useFlow
from Kotlin coroutines. -
Pager
takes two parameters:-
PagingConfig
, defines howPagingSource
should load the data.pageSize
specifies how many items to load in a single page.enablePlaceholders
indicates whether you want to display placeholders when loading the data. Here you set it tofalse
. - The second parameter is a trailing lambda that returns a
PagingSource
. In this case, you useRedditPagingSource
with theredditService
you created earlier.
-
Flow
, take a look at this Kotlin Flow for Android: Getting Started tutorial.
Finally, when the IDE prompts you, make sure you add the imports to resolve the errors. In case of importing Flow
, choose the one from Kotlin Coroutines.
In the next section, you’ll make use of fetchPosts()
from the ViewModel to trigger the API call for fetching list of posts from Reddit API.