android-pagingandroid-paging-libraryandroid-paging-3

Jetpack Paging3 RemoteMediator returns same PagingSatate on #load append


I'm following this codelab to build an paging3 app with github API and a local DB. While the first 2 pages load fine, the mediator hits a loop when trying to load the 3rd page when scrolling to bottom - the same PagingState is passed to load() function over and over.

Just wondering if anyone knows what could be the possible root cause here?

Some implementation details:

RemoteMediator: (the prevPage and currentPage is from github API's pagination response header and saved to a local DB.)

// RepositoryMediator
override suspend fun load(
    loadType: LoadType,
    state: PagingState<Int, Repository>
): MediatorResult {
    return when (loadType) {
        LoadType.REFRESH -> {
            fireRequestForPage(1, true /*clear DB*/)
            return Success(endOfPaginationReached = false)
        }

        LoadType.APPEND -> {
            // !!!!!!! kept getting the same state when APPEND is triggered, resulting in same currentPage and nextPage
            // get currentPage, nextPage from state.lastItemOrNull
            if(currentPage < nextPage) {
              fireRequestForPage(nextPage)
              Success(endOfPaginationReached = false)
            } else {
              return Success(endOfPaginationReached = true)
            }
        LoadType.PREPEND -> {
            // get currentPage, prevPage from state.firstItemOrNull
            if(currentPage > prevPage) {
              fireRequestForPage(prevPage)
              Success(endOfPaginationReached = false)
            } else {
              return Success(endOfPaginationReached = true)
            }
        }
    }
}

Observable: I'm using liveData instead of flow to from the Pager:

fun searchRepositoryWithUserId(userLoginName: String): LiveData<PagingData<Repository>> {
    // need to create a new Pager each time because the search query is different
    return Pager(
        config = PagingConfig(pageSize = PAGE_SIZE, enablePlaceholders = false),
        remoteMediator = RepositoryMediator()
    ) {
        repoDao().getRepositoriesOfUser(userLoginName)
    }.liveData
}

Dao: just a plain query

@Query("SELECT * FROM repository_table WHERE login = :ownerLoginName")
fun getRepositoriesOfUser(ownerLoginName: String): PagingSource<Int, Repository>

Solution

  • For anyone interested, the fix is from Dao, need to update the query to sort on reponame, otherwise the query will return the same last Page for PagingSource even if there're new items inserted into DB, confusing the Mediator.

    @Query("SELECT * FROM repository_table WHERE login = :ownerLoginName ORDER BY repository_name ASC")
    fun getRepositoriesOfUser(ownerLoginName: String): PagingSource<Int, Repository>