Paging 3 provides a Paging library based on RecyclerView to handle various functions such as page turning, loading more and refreshing for users, which can effectively optimize the logic of this part of the code.

1. Reference dependencies

implementation "Androidx. The paging: the paging - runtime: 3.0.0 - alpha02"
Copy the code

For details, see Paging 3 Library Overview

2. Load the data source

2.1 Room

When defining the Query statement of the Dao interface, the return type is of type PagingSource, and the second parameter is the data structure of the table. The number of pages per page is controlled by PagingSource. The number of pages per page is defined in PagingConfig.

@Dao
interface CheeseDao {
    @Query("SELECT * FROM Cheese ORDER BY name COLLATE NOCASE ASC")
    fun allCheesesByName(a): PagingSource<Int, Cheese>

    @Insert
    fun insert(cheese: Cheese)

    @Delete
    fun delete(cheese: Cheese)
}
Copy the code

One advantage of using Room is that if you modify the data in Room by insert() or delete(), it will be immediately reflected in the PagingSource, and the data displayed in the interface will change accordingly.

2.2 Customizing data sources

If you do not use Room data directly, but use data from other places, such as network data, you need to customize the PagingSource, which is created as follows:

class PageKeyedSubredditPagingSource(
        private val redditApi: RedditApi,
        private val subredditName: String
) : PagingSource<String, RedditPost>() {
    override suspend fun load(params: LoadParams<String>): LoadResult<String, RedditPost> {
        return try {
            val data = redditApi.getTop(
                    subreddit = subredditName,
                    // The type of the key class is the key in PagingSource< key: Any, Value: Any>. The specific Value is user-defined. Null when first called
                    after = if (params is Append) params.key else null,
                    before = if (params is Prepend) params.key else null,
                    limit = params.loadSize // loadSize indicates the amount of requested data
            ).data

            Page(
                    data = data.children.map { it.data },
                    prevKey = data.before,
                    nextKey = data.after
            )
        } catch (e: IOException) {
            LoadResult.Error(e)
        } catch (e: HttpException) {
            LoadResult.Error(e)
        }
    }
}
Copy the code

3. Construct Pager and PagingData

val allCheeses: Flow<PagingData<Cheese>> = Pager(
    PagingConfig(
        // The size of the data displayed per page. Corresponding to loadparams. loadSize in PagingSource
        pageSize = 20.// The pre-refresh distance, how far from the last item to load data
        prefetchDistance = 3.// Initialize the number of loads. Default is pageSize * 3
        initialLoadSize = 60.// The maximum amount of data that should be stored in memory at one time
        maxSize = 200)) {// The data source is required to return an object of type PagingSource
    dao.allCheesesByName()
}.flow // Finally construct and external interaction objects, there are two kinds of flow and liveData
Copy the code

4. Construct a custom PagingDataAdapter

class CheeseAdapter : PagingDataAdapter<Cheese, CheeseViewHolder>(diffCallback) {
    override fun onBindViewHolder(holder: CheeseViewHolder, position: Int) {
        holder.bindTo(getItem(position))
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CheeseViewHolder =
            CheeseViewHolder(parent)

    companion object {
        private val diffCallback = object : DiffUtil.ItemCallback<Cheese>() {
            override fun areItemsTheSame(oldItem: Cheese, newItem: Cheese): Boolean =
                    oldItem.id == newItem.id
            override fun areContentsTheSame(oldItem: Cheese, newItem: Cheese): Boolean =
                    oldItem == newItem
        }
    }
}
Copy the code

The PagingDataAdapter only needs to pass in the DiffUtil.itemCallback object in the constructor, without defining and passing data. Then it will associate with PagingData and use the data of PagingData. If you need to get data at a location, use the getItem() method in your class.

In the custom PagingDataAdapter, you only need to implement the onBindViewHolder() and onCreateViewHolder() methods.

5. Link data

val adapter = CheeseAdapter()
recyclerView.adapter = adapter

lifecycleScope.launch {
    viewModel.allCheeses.collectLatest { adapter.submitData(it) }
}
Copy the code

Reference article:

Android Jetpack Page Library overview

Jetpack member Paging3 Practice and Source Code Analysis (PART 1)

JetPack Series Paging 3.0 learning