Android jetpack paging 3

Pagination in Android with Paging 3, Retrofit and kotlin Flow

Haven’t you asked how does Facebook, Instagram, Twitter, Forbes, etc… let you “scroll infinitely” without reach a “end” of information in their apps? Wouldn’t you like to implement something like that?

This “endless scrolling” feature is commonly called “Pagination” and it’s nothing new. In a brief resume, pagination help you to load chunks of data associated with a “page” index.

Let’s assume you have 200 items to display in your RecyclerView. What you would do normally is just execute your request, get the response items and submit your list to your adapter. We already know that RecyclerView by it’s own is optimized for “recycle our views”. But do we really need to get those 200 items immediately? What if our user never reach the top 100, or top 50? The rest of the non displayed items are still keep on memory.

What pagination does (in conjunction with our API) is that it let us establish a page number, and how many items per page can we load. In that way, we can request for the next page of items only when we reach the bottom of our RecyclerView.

Non library approach

Before paging 3, you could have implemented Pagination by adding some listeners to your RecyclerView and those listeners would be triggered when you reach the bottom of your list. There are some good samples about it, here is a video with a vey detailed explanation (it’s on Indi, but it is understandable anyways).

A real PRODUCTION ready example is on the Plaid app. Look at their InfinteScrollListener class.

Android Jetpack Paging 3 and Flow

Today you gonna learn how to implement Pagination by using paging 3 from the android jetpack libraries. For my surprise the codelab of Paging 3 was one of the most easiest I have ever done. Florina Muntenescu did a great job with each step of the codelab, go check it out and give it a try. If you want to go straight to the sample code, check this pull request and see step by step how I implement paging 3 to this project.

Источник

Overview

Benefits of using paging library

The paging library contains the following functions:

  • In-memory cache of paged data. This ensures that your application uses system resources effectively when processing page data.
  • The built-in request deduplication function ensures that your application effectively uses network bandwidth and system resources.
  • Configurable RecyclerView The adapter automatically requests data when the user scrolls to the end of the loaded data.
  • For Kotlin coroutines and Flow and LiveData support .
  • Built-in error handling support, including refresh and retry functions.

Architecture design

The paging library is part of the Android recommended architecture design. The components of the library involve a three-tier structure in the use of applications.

  • The repository layer
  • The ViewModel layer
  • The UI layer

The figure above describes the paging library components running on each layer and how they work together to load and display paging data.

Repository layer

The main paging library components in the repository layer are PagingSource . Each PagingSource Objects define a data source and how to retrieve data from that source. PagingSource Objects can load data from any single source, including network sources and local databases.

Another paging library component you might use is RemoteMediator 。 RemoteMediator Objects are used to process hierarchical data sources, such as network data sources with local database caches.

ViewModel layer

The Pager The component provides a public API for constructing PagingData Object (based on PagingSource , The instance exposed in the response stream) and PagingConfig Configure the object.

will ViewModel The components that connect the layer to the UI are PagingData 。 PagingData The purpose is to be a container for snapshots of paged data. It queries a PagingSource Object and store the result.

UI layer

The main paging library components in the UI layer are PagingDataAdapter , RecyclerView Adapter used to process paged data.

Alternatively, you can use the attached AsyncPagingDataDiffer Component to build your own custom adapter

**Note:** If your application usesCompose for UI, please use androidx.paging:paging-compose The artifact integrates Paging with the UI layer. To learn more, please refer to the API documentation collectAsLazyPagingItems() 。

Load and display the paged data stream of the network data source

Define the data source

The first step is to define a PagingSource Implement to identify the data source. The PagingSource API classes include load() Method, it must be rewritten to indicate how to retrieve the paged data from the corresponding data source.

PagingSource Use this class directly to use Kotlin coroutines for asynchronous loading.

The Paging library also provides classes that support other asynchronous frameworks:

  • To use RxJava, please change to RxPagingSource 。
  • want ListenableFuture Used in Guava, instead ListenableFuturePagingSource 。

Select key and value type

PagingSource There are two type parameters: Key with Value . The key defines the identifier used to load the data, and the value is the type of the data itself.

Читайте также:  Фонд социального страхования андроид

For example, if you pass Int Page number toRetrofit, Loaded from the web User The paging data of the object.

Should choose Int As Key Types of, User As Value Types of.

Define PagingSource

The following example implements a PagingSource Load paging data by page number. The Key Type is Int versus Value Types of User 。

a typical PagingSource The implementation passes the parameters provided in its constructor to the load() Method to load the appropriate data for the query.

In the example above, these parameters are:

  • backend : An instance of a back-end service that provides data.
  • query : Search query to send to the indicated service backend 。

The LoadParams The object contains information about the load operation to be performed. This includes the key to be loaded and the number of items to be loaded.

The LoadResult The object contains the result of the load operation. LoadResult Is a sealed class that takes one of two forms, depending on load() Whether the call was successful:

If the load is successful, it returns a LoadResult.Page Object.

If the load is unsuccessful, it returns a LoadResult.Error Object.

The figure below illustrates load() How does the function in this example receive a key for each load and provide a key for subsequent loads.

Handling errors

The request to load data may fail for a variety of reasons, especially when loading over the network.

by LoadResult.Error From load() The method returns an object to report errors encountered during loading.

For example, you can ExamplePagingSource By adding the following to load() Method to capture and report the loading error in the previous example:

For more information on handling retrofit errors, see PagingSource Examples in the API reference.

PagingSource collect LoadResult.Error Objects and pass them to the UI so that you can manipulate them. For more information about exposing the loading status in the UI, seeShow loading status。

Set up the PagingData stream

Next, you need to implement the paging data flow PagingSource 。

Generally, you should be ViewModel Set the data flow in. Pager The class provides methods that can be obtained from PagingSource Response stream PagingData Object.

The paging library supports the use of multiple stream types, including Flow , LiveData with Flowable with Observable Type from RxJava.

create Pager Instance to set up the response flow, you must provide a PagingConfig Configuration object and a function that tells Pager How to obtain an implementation instance PagingSource :

cachedIn() Method passed in CoroutineScope Provide a data stream and cache the loaded data.

Pager Object from PagingSource Call in load() Method, pass to it LoadParams Object and receive LoadResult 。

Define a RecyclerView adapter

You also need to set up the adapter to receive data RecyclerView List.

Paging library PagingDataAdapter Classes are provided for this.

Define an extensible class PagingDataAdapter . In this example, UserAdapter inherit PagingDataAdapter As RecyclerView Provide adapter, list type User , UserViewHolder Used asViewHolder:

Your adapter must also define onCreateViewHolder() with onBindViewHolder() Method and specify DiffUtil.ItemCallback :

Display paged data in the user interface

Now you have defined a PagingSource , Which generates a data stream for your application PagingData And defines a PagingDataAdapter , You can connect these elements together and display the paging data in the activity.

In activity onCreate Or fragment onViewCreated The method performs the following steps:

  1. Create your PagingDataAdapter Instance of the class.
  2. will PagingDataAdapter Instance passed to RecyclerView To display a list of paged data.
  3. Observed PagingData Stream and pass each generated value to the adapter’s submitData() method.

RecyclerView It is now possible to display paged data from the data source and automatically load another page when necessary.

Show loading status

The paging library exposes the loading status in order to pass LoadState The object is used in the UI.

LoadState According to the current loading status, one of the following three forms is adopted:

  • If there is no active load operation and no errors, LoadState Then LoadState.NotLoading Object.
  • If there is an active load operation, LoadState Then LoadState.Loading Object.
  • If there is an error, then LoadState Is an LoadState.Error Object.

LoadState There are two ways to use it in the UI:

  • Use loading status monitoring
  • Use a special list adapter.

Use the listener to get the loading status

To get the loading status usually used in the UI, please PagingDataAdapter contain addLoadStateListener() method.

Use adapter to display loading status

The paging library provides another list adapter LoadStateAdapter , Its purpose is to directly display the loading status in the displayed page data list.

First, create an implementation class LoadStateAdapter And define onCreateViewHolder() with onBindViewHolder() method:

then, withLoadStateHeaderAndFooter() From your PagingDataAdapter Call this method in the object:

Источник

Android jetpack paging 3

Android sample code for new Jetpack Paging3 Library Paging3 is one of the new Jetpack libraries for managing and loading a large chunk of the dataset from various data sources efficiently. It allows us to load pages of data from the network or local database with ease and saves our development time.

  • It caches the paged data in-memory for better usage of the system resources which not only gives fast response but also helps in data loading without hiccups.
  • It handles the network request duplication very elegantly hence saving the user’s bandwidth and system resources.
  • A much flexible Recyclerview Adapter which requests & loads the data gracefully whenever the user reaches near the end of the page, yes now adapter is controlling when and what to load with one-time setup.
  • It is Kotlin first means the whole library is written in Kotlin and works very well with other offerings of the Kotlin like Coroutines and Flow. Also, it supports the much-used libraries like RxJava and LiveData as well.
  • It has inbuilt support for error handling, retry and refresh use cases.
Читайте также:  Облако яндекс андроид войти

Feel free to fork or pull and play with the new Paging3.

Let’s connect or reach out for suggestions or improvements.

Social Profile
Twitter @vikaskum09
LinkedIn @vikaskumar09

About

Android sample code for new Jetpack Paging3 Library

Источник

Paging 3 Android Tutorial

When working with RecyclerViews in our Android project, we display a list with a lot of items in it. Sometimes we have use-case like fetching a contact list from the phone and displaying it on the list. Loading a lot of data at once in a list is not a very efficient task to do. To get over this, we have paging in Android.

By using the Paging library, we can load a lot of data efficiently, and only we will load the data when needed. In this blog, we will be learning about the Paging 3 library in Android and how we can use it to load our large set of data in our RecyclerView efficiently.

In this blog, we are going to learn,

  • Introduction to Paging 3 library
  • Understanding and Implementing Paging 3 library.
  • Getting the States of the data
  • Adding the Header and Footer view.
  • Using it with RxJava.

Introduction to Paging 3 library

Google launched Paging 3 as a part of the Jetpack series. It is still in the early stages. Paging 3 is written entirely using Kotlin Coroutines. It has support for requesting the next page to load more data automatically. It supports Flow, LiveData, and RxJava along with Kotlin Coroutine.

Paging 3 also adds support for caching and handles the state efficiently like loading and failed states while loading the items on ti the list. It also keeps track for the keys to get data from the next and previous pages.

Understanding and Implementing Paging 3 library

In this, we are going to learn implementing Paging 3 library by fetching the list from an API and displaying it in the list. We are going to use the following API for displaying the list,

Our project structure looks like,

Here, we have an adapter package which is responsible for displaying the list in the RecyclerView. data package is responsible for fetching data from the API. We also have MainActivity in which we are going to display the list.

So, now let’s get started.

Step 01.

Let’s first setup the dependencies for Paging 3 in our app’s build.gradle like,

Note: At the time of writing the blog, its version is 3.0.0-alpha04

and we will also add the support for Retrofit and Moshi as we are going to use Moshi as convertor factory for Retrofit like,

Step 02.

Now, we are going to setup APIService and Retrofit client like,

Here, we have created an APIService interface with getListData function which takes a query parameter which will take the page number from which we have to fetch the data from.

We also setup the Retrofit client, by adding the base URL and the convertor factory of Moshi.

Step 03.

Now, we have to create the data class for the following JSON output which we get as the response,

and we create the corresponding data classes for the above JSON response. Our ApiResponse data class looks like,

The Ad data class looks like,

and Data data class looks like,

Step 04.

Now, since we have setup the data class and APIService, let’s setup the paging library. In PostDataSource we will update the code as,

Here, we have extended PostDataSource with PagingSource which will implement a suspend load function which will help us to load the data.

PostDataSource also takes a primary constructor parameter APIService. PostDataSource acts here as a repository and the load function gets the data from the API.

Since the load function is a suspend function, we can call other suspend functions inside it without any issues which we created in APIService.

In the PostDataSource, we take two parameters one of integer type and other of the data type we have to load on the list item. The integer parameter represents the page number here.

Now, we update the load function like,

Here, we get the page number from params and assign it to nextPage variable using param.key and if it returns null, we set a default value 1.

We also do the API call and get assign the response to the response variable using APIService which we passed as a constructor parameter to PostDataSource class.

After doing all the operations with the successful response, we return the LoadResult.Page object here with the required data and it something went wrong we use LoadResult.Error.

We are also passing null as the next key if there is no corresponding data in that direction.

Here, the PostDataSource is responsible to keep track of the page which has to be requested next which we get from the APIService.

Step 05.

Now, since we have the DataSource setup we will now get the data in the MainViewModel. We will create the MainViewModel by adding the APIService as a parameter to the primary constructor. So, we will update the ViewModel like,

Now, inside the ViewModel, we will create a variable called listData and assign it to the Pager instance.

Here, the Pager will call the load function from the PostDataSource and we will pass the apiService as well in the object of PostDataSource.

In the Pager object, we also pass the configuration which is used to configure the behavior of Paging and how it should load its data. We are passing the PagingConfig with the pageSize.

PageSize specifics the number of items loaded at once from the PostDataSource. Recommended is to always keep the page size to more than the visible items on the screen.

And lastly, we will convert the listData as flow by adding .flow .

It will convert the stream of data into a Flow. If we want to return LiveData we can replace .flow with .liveData.

And at last, we cache the data in viewModelScope, and the data will be alive until the scope is active. Here, we are using viewModelScope and since we are caching the data in the ViewModel it would not be impacted on any configuration changes.

Step 06.

Now, since we are getting the data in ViewModel, we now need to pass the data in the RecyclerView of MainActivity. We will update the activity_main.xml like,

Now, we will update the MainActivity like,

Here, we have setup our ViewModel by passing the MainViewModelFactory with the instance of APIService.

The MainViewModelFactory looks like,

And then we have to setup the RecyclerView in the setupList function and lastly, in the setupView function, we will collect the data from listData variable from ViewModel inside the lifecycleScope and then pass it to the submitData function which is part of PagingDataAdapter which helps us to update the data we fetched from the API and display in the UI.

Step 07.

Now, we will update the MainListAdapter. We will extend the MainListAdapter with PagingDataAdapter and the PagingDataAdapter will take the type of data we need to display in the list and the ViewHolder.

It also takes a DiffUtil callback, as a parameter to its primary constructor which helps the PagingDataAdapter to update the items if they are changed or updated. And DiffUtil callback is used because they are more performant.

Now, the MainListAdapter looks like,

Here, in the MainListAdapter, inside the onCreateViewHolder we are returning the ViewHolder by inflating the R.layout.list_item.

Here, the list_item layout file looks like,

and inside the onBindViewHolder we will assign the full name and email to both the TextViews.

And when we run the app, we will see the desired output on the screen and when we scroll the list to the bottom it will load the item from the second page and so on.

Getting the States of the data

Now, while loading the data we might also want to show progress view, and when we have loaded the data we should hide the progress view.

To react to the states of data we use addLoadStateListener like,

Here, we get the CombinedLoadState in addLoadStateListener and we use this to show or hide the progress views.

We can also react to errors inside the addLoadStateListener if all the state methods like refresh, append, and prepend are instance of LoadState.Error.

Now, since we have successfully integrated the Paging 3 library, now we will see how we can setup a footer view and header view.

FooterView is the one that when we go the last item of the list and the data is getting loaded from the next page, the footer view gets displayed. And as soon as the data is loaded the footer view is hidden.

For creating these views we will create a RecyclerViewAdapter similar to how we do in general use of RecyclerViews.

But in this case, we will extend the RecyclerView with LoadStateAdapter and pass the ViewHolder to it like,

Here, inside the onBindViewHolder, we get an additional parameter now of LoadState which we can use to show or hide the loading view based on if the data is getting loaded or not and add it to the adapter we use withLoadStateHeaderAndFooter like,

If we want to just add a footer we will use,

and to use with header we use,

And now, if the data is getting loaded from the paging library, the footer/header is displayed based on which one or both are attached to the RecyclerView adapter.

Using it with RxJava

If we don’t want to use it with Coroutines and Flow and want to go ahead and use RxJava, we still need to follow the above steps but with few changes.

Let me list them down.

Step 01.

First, we need to add the dependencies for Paging 3 Rx support,

and we will also add the dependency for RxJava2 adapter factory,

Step 02.

Now, as a next step, we need to update the PostDataSource and extend it using RxPagingSource in place of PagingSource like,

Now, the PostDataSource will implement the loadSingle function of return type Single like,

Step 03.

Now, we will update the APIService interface like,

Here, the getListData returns a Single and is not a suspend function anymore. And we have added another adapter factory to support RxJava2 to the Retrofit builder.

Step 04.

Now, inside the loadSingle function, we can do our tasks and return LoadResult.Page object if the output is successful or LoadResult.Error if it isn’t.

And to get the data from the PostDataSource to ViewModel we will update the listData variable in MainViewModel like,

This will return a Flowable of PagingData and their rest remains the same as above.

We can also pass make listData of type Observable of PagingData like,

The MainListAdapter remains untouched and in the setupView function in MainActivity gets updated like,

Here, we are passing the lifecycle of the View and the paging data to submit data to inflate the list.

This is how you can use the Paging 3 library with RxJava as well.

Conclusion

Paging 3 library is still in its early stage and it is completely re-written using Kotlin coroutines but it can be used with Flow and RxJava both.

Источник

Читайте также:  Леон букмекерская контора мобильная версия андроид
Оцените статью