Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Same value was passed as the nextKey in two sequential Pages loaded from a PagingSource in Paging Library 3 Android

I migrated from paging 2 to paging 3. I tried to implement ItemKeyedDataSource of Paging 2 to Paging library 3. But the problem I was facing is, the same value(currentJodId) was passed as the nextkey in two sequential Pages loaded. And After that app crashes. but if I add "keyReuseSupported = true" in DataSource, app does not crash. But it started calling same item id as the nextkey.

JobSliderRestApi.kt

@GET("job/list/slides")
fun getDetailOfSelectedJob(
    @Query("current_job") currentJodId: Int?,
    @Query("limit") jobLimit: Int?,
    @Query("search_in") fetchType: String?
): Single<Response<JobViewResponse>>

JobViewResponse.kt

data class JobViewResponse(
    @SerializedName("data") val data: ArrayList<JobDetail>?
) : BaseResponse()

JobDetail.kt

data class JobDetail(
    @SerializedName("job_id") val jobId: Int,
    @SerializedName("tuition_type") val jobType: String?,
    @SerializedName("class_image") val jobImage: String,
    @SerializedName("salary") val salary: String,
    @SerializedName("no_of_student") val noOfStudent: Int,
    @SerializedName("student_gender") val studentGender: String,
    @SerializedName("tutor_gender") val preferredTutor: String,
    @SerializedName("days_per_week") val daysPerWeek: String?,
    @SerializedName("other_req") val otherReq: String?,
    @SerializedName("latitude") val latitude: Double?,
    @SerializedName("longitude") val longitude: Double?,
    @SerializedName("area") val area: String,
    @SerializedName("tutoring_time") val tutoringTime: String?,
    @SerializedName("posted_date") val postedDate: String?,
    @SerializedName("subjects") val subjects: String,
    @SerializedName("title") val title: String
)

JodSliderDataSource.kt

class JodSliderDataSource @Inject constructor(
    private val jobSliderRestApi: JobSliderRestApi
): RxPagingSource<Int, JobDetail>() {

//    override val keyReuseSupported = true

    @ExperimentalPagingApi
    override fun getRefreshKey(state: PagingState<Int, JobDetail>): Int? {
        return state.anchorPosition?.let {
            state.closestItemToPosition(it)?.jobId
        }
    }

    override fun loadSingle(params: LoadParams<Int>): Single<LoadResult<Int, JobDetail>> {
        return jobSliderRestApi.getDetailOfSelectedJob(42673, 2, "next").toSingle()
            .subscribeOn(Schedulers.io())
            .map { jobResponse -> toLoadResult(jobResponse.data) }
            .onErrorReturn { LoadResult.Error(it) }
    }

    private fun toLoadResult(data: ArrayList<JobDetail>): LoadResult<Int, JobDetail> {
        return LoadResult.Page(data = data, prevKey = null, nextKey = data.lastOrNull()?.jobId)
    }
}
like image 465
Aminul Haque Aome Avatar asked Sep 13 '20 11:09

Aminul Haque Aome


People also ask

What is getRefreshKey in Paging 3?

The getRefreshKey method load() (the first call is initial load which uses the initial key provided to the Pager). A refresh happens whenever the Paging library wants to load new data to replace the current list, e.g., on swipe to refresh or on invalidation due to database updates, config changes, process death, etc.

How can I get data from PagingData?

Display the paged data in your UICreate an instance of your PagingDataAdapter class. Pass the PagingDataAdapter instance to the RecyclerView list that you want to display your paged data. Observe the PagingData stream, and pass each generated value to your adapter's submitData() method.

What is getRefreshKey?

getRefreshKey() provides a key used for the initial load for the next pagingSource due to invalidation of the existing pagingSource . The key is provided to load via LoadParams. key . The last accessed position can be retrieved via state.

What is the difference between prevkey and nextkey in pagingsource?

{ // * prevKey == null -> anchorPage is the first page. // * nextKey == null -> anchorPage is the last page. // just return null. A typical PagingSource implementation passes parameters provided in its constructor to the load () method to load appropriate data for a query. In the example above, those parameters are:

What is the difference between the key and value types of pagingsource?

PagingSource<Key, Value> has two type parameters: Key and 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 load pages of User objects from the network by passing Int page numbers to Retrofit , you would select Int as the Key type and User as the Value type.

How do I load paged data in Kotlin using async?

The PagingSource API class includes the load () method, which you must override to indicate how to retrieve paged data from the corresponding data source. Use the PagingSource class directly to use Kotlin coroutines for async loading. The Paging library also provides classes to support other async frameworks:

What is paging3 and how to use it?

It allows us to load pages of data from the network or local database with ease and saves our development time. Paging3 is designed to follow the Android app architecture and coordinates with other Jetpack components.


1 Answers

I was getting the same error and this is what worked for me. In the JodSliderDataSource class, toLoadResult method, set the nextKey parameter value by getting the page number from the response data and adding one.

    private fun toLoadResult(
        data: ArrayList<JobDetail>
    ): LoadResult<Int, JobDetail>  {
        return LoadResult.Page(
        data = data, 
        prevKey = null,
        nextKey = data.lastOrNull()?.jobId + 1 // Add one to the page number here.
    )
}
like image 95
David Wekesa Avatar answered Oct 21 '22 08:10

David Wekesa