C.Chee
C.Chee

Reputation: 55

Android RecyclerView Paging issue

I am following this example to implement the paging library, using the TMDB Api.

As I scroll down the list reaching a boundary condition, it will always scroll back up to page 1.

I think there is some issues going on with the RemoteMediator class causing this issue, but I am almost copying from the Google example...

Below is my log. I am scrolling down the list here.Log

I guess the problem is that "LoadType = PREPEND" is called as I scroll down the list. The adapter first APPEND the next page, but then detects a boundary condition at the top of the next page and decide to do a PREPEND, which cause the issue? I am not sure how to solve this issue. I have tried changing the config of the pager, but it doesn't work.

You may find my code here.

Thanks in advance!

Upvotes: 3

Views: 2170

Answers (2)

binzhi lai
binzhi lai

Reputation: 1

I have encountered the same problem, but I have found a solution. This should be because of the database index. Check the primary key of your entity class, which is generally the id, but the size of the id should be messy. When Room inserts the data, it will be inserted according to the size of the primary key, which causes your database and api The data order of the response is wrong.

The solution is to redefine another primary key in your entity class and let it grow automatically, like databaseId,so that the insertion order of the Room database is correct. This can solve the problem of list sliding

@Entity(tableName = "articles")
data class Article(
    @PrimaryKey(autoGenerate = true)
    val databaseId: Int,
    @field:SerializedName("id")
    val id: Int,
    @field:SerializedName("title")
    val title: String,
    @field:SerializedName("apkLink")
    val apkLink: String,
    @field:SerializedName("audit")
    val audit: Int

Upvotes: 0

Eduardo macedo
Eduardo macedo

Reputation: 822

I had the same problem, but for me the solution was removing the following lines from the SearchRepositoriesActivity:

private fun initSearch(query: String) {

    /* Some code here */

    // Remove these lines
    /*
    lifecycleScope.launch {   
        @OptIn(ExperimentalPagingApi::class)
        adapter.dataRefreshFlow.collect {
            binding.list.scrollToPosition(0)
        }
    }
    */
}

You can see it here on the repository. This was introduced in the codelab so that the RecyclerView scrolled back to the top once a request (for a new repository search) is completed, which was exactly what was happening with me: The RecyclerView only went up after the OkHttp logged that it received the result from the request.

I can't understand completely why this was working with the network only implementation, but not with the network + database. If I understand the code correctly, this stream should only be notified when an LoadState.REFRESH event happens. I believe there's a hidden LoadState.REFRESH that's being sent but it's not received on the RemoteMediator. Once I removed the code above, the screen still flickers because it moves to a Loading state really quickly. You can see it by adding a Log to the addLoadStateListener (available here) like so:

adapter.addLoadStateListener {  loadState ->
        // Add this log
        Log.d("UI_PAGING", "source: ${loadState.source.refresh}, remote: ${loadState.refresh}")

        // Only show the list if refresh succeeds.
        binding.list.isVisible = loadState.source.refresh is LoadState.NotLoading
        // Show loading spinner during initial load or refresh
        binding.progressBar.isVisible = loadState.source.refresh is LoadState.Loading
        // Show the retry state if initial load or refresh fails.
        binding.retryButton.isVisible = loadState.source.refresh is LoadState.Error

        /* some other code here */
}

which shows the following logs:

Android Logs for Paging Library 3

As you can see Room is changing the refresh state once the append happens.

Upvotes: 2

Related Questions