Portal Berita dan Informasi Terbaik di Indonesia

Clone Series – Part 2: Building a YouTube clone using Paging 3 | by Divyansh Saraswat | May, 2022

Photo by Matt Hudson on Unsplash

This tutorial teaches us how to display the most popular YouTube video content in a RecyclerView using the Paging library.

Check out my previous article on the Google News clone, Part 1 of this series.

This is what we are trying to implement:

screen showing the button for retrying the network request

The main trick is to override the getRefreshKey function in our PagingSource implementation so that it updates the pageToken parameter based on the API response.

Look at this step of the basic paging codelab for an overview of the PagingSource implementation.

As you would have noticed, first we acquire the closest page centered around the anchorPosition, take its prevKey, and then make the API call using this prevKey as the query parameter pageToken in the function getMostPopularVideos().

Finally, the response from the API gives us nextPageToken which is nothing but the current pageToken or ‘refresh key’ because this page was accessed using its prevKey.

All of this is done in a separate CoroutineScope which is injected using Hilt.

In YouTube Data API, getting the profile/thumbnail image of a YouTube channel involves a different endpoint, so we need to make a separate API request for this task.

First, let us create a data class that holds a video-item field and a string field for the channel’s image-URL.

data class VideoWithChannelModel(
val item: Item,
val channelUrl: String
)

Then the part where we apply transformations to the ‘Pager.flow' in our ViewModel:

  • Use the map operator as a transform on the upstream flow which contains PagingData<Item> as an emitted value.
  • On each emitted value, apply another map transform (this one is provided by the paging library).
  • Make the API call associated with the ‘channels’ endpoint inside the map function (since map is a suspend function).
  • Store the item and channelUrl fields in the data class and return them from the map function.
  • Now this Flow is of type PagingData<VideoWithChannelModel>.

The complete implementation for VideoViewModel looks like this:

Repository’s implementation:

The PagingDataAdapter also needs to hold items that are of the type VideoWithChannelModel

There are two ways in which the loading state of the UI can be presented to the user:

  1. On the main screen, by ‘collecting’ the loadStateFlow from the PagingDataAdapter.
  2. At the end of the list, when more items are being loaded.

For now, we concentrate on implementing the second part.

This is done by creating separate classes that extend RecyclerView.ViewHolder and LoadStateAdapter respectively and creating a separate layout file for the recycler-view item.

We primarily need information on:

  1. How to retry the network request (done by defining retry: () -> Unit as a constructor argument).
  2. loadState as a parameter of the bind method (the type LoadState is already provided by the Paging library).

Following is the implementation of the steps discussed above:

As specified in this task of Kotlin Koans :

Objects with the invoke() method can be invoked as a function.

Hence we wrote retry.invoke() in the setOnClickListener ‘s lambda.

The Adapter class which takes a function as an argument :

And finally the layout file:

All done, the only remaining step is to observe/collect the loading state in our UI.

As you can see in the fragment’s implementation, we pass the function adapter.retry() as a lambda argument in the VideoLoadStateAdpapter.

adapter.withLoadStateFooter() is used when items are to be loaded only at the end of the list.

For more information, check out this step of the advanced paging codelab.

Learning Resources:

  1. Paging Basic Codelab
  2. Paging Advanced Codelab
  3. Part 1 of the series:

4. Android Developers’ blog post:

5. ‘Safely’ collecting Flows in the UI layer:

Link to this project’s GitHub repository:

Leave a Reply

Your email address will not be published.