Has anyone had any issues with the Paging 3.0 Libr...
# compose
b
Has anyone had any issues with the Paging 3.0 Library duplicating data? Every time a new page is requested, it loads the new data but then overwrites all of the previous data with the new data. See code in thread:
Copy code
private val postsPagingSource by lazy { PostsPagingSource(redditApi) }

    private val posts = Pager(
        config = PagingConfig(
            enablePlaceholders = false,
            initialLoadSize = 5,
            pageSize = 5,
            prefetchDistance = 20
        ),
        initialKey = null,
        pagingSourceFactory = { postsPagingSource }
    ).flow.cachedIn(this)
Copy code
package com.bohregard.pagertest.web.paging

import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.bohregard.pagertest.extension.debug
import <http://com.bohregard.pagertest.model.Post|com.bohregard.pagertest.model.Post>
import com.bohregard.pagertest.web.RedditApi
import java.lang.Exception

class PostsPagingSource(
    val redditApi: RedditApi
): PagingSource<String, Post>() {

    companion object {
        private var _lastFetchedPosts = listOf<Post>()
    }

    override suspend fun load(params: LoadParams<String>): LoadResult<String, Post> {
        debug("Loading...${params.key}")
        try {
            val response = redditApi.getAllPosts(
                "r/all",
                "hot",
                params.key,
                null
            )

            val loadResult = LoadResult.Page(
                data = response.posts,
                prevKey = params.key,
                nextKey = response.after,
            )
            _lastFetchedPosts = response.posts
            return loadResult
        } catch (e: Exception) {
            return LoadResult.Error(e)
        }
    }

    override fun getRefreshKey(state: PagingState<String, Post>): String? {
        debug("Refresh Key")
        return null
    }
}
Copy code
PagerTestTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    val posts = posts.collectAsLazyPagingItems()
                    debug("Testing...")
                    LazyColumn {
                        items(posts) { post ->
                            Box(
                                contentAlignment = Alignment.Center,
                                modifier = Modifier.padding(10.dp)
                            ) {
                                Text("Post: ${post!!.title}")
                            }
                        }
                    }
                }
            }
i
Isn't that exactly what you're doing when you say
_lastFetchedPosts = response.posts
? You'd want to append the newly loaded data, not replace the entire set, right?
Also storing that data in a
companion object
seems very suspicious in general
b
Last fetch post isnt actually being used by anything
But I absolutely want the data to be appended
The companion object was just me at my Wit's end trying to do literally anything to get it to work
But if you look at the load result it's using the response that comes back instead
i
Where is that first snippet of code located? (What is the
this
passed to
cachedIn
?)
Maybe @Dustin Lam has some ideas
b
This is an activity
It extends coroutine scope
Fwiw this is a very small project to recreate this issue since in my larger project it's in a view model and so the cached in is just the view model scope.
Here is a repo with what I’m seeing if that makes things easier: https://github.com/bohregard/Pager-Test
d
I'm not at a computer atm, but just quickly looking, there's a few things you should fix: prevKey should only be non-null if you expect to prepend additional data, it looks like you'd just reload the same page perpetually with your current implementation pass the key mapping arg in items(lazyPagingItems), it helps compose understand how to keep scroll position when prepending data, this is probably why it looks like your data is getting "replaced" combined with the redundant prepend above You should always return a new instance of PagingSource in the factory, don't stash the same one and re-use it.
Although I'm a bit surprised this doesn't crash because we disallow re-using keys like this by default, specifically to catch this mistake unless you explicitly opt-in
b
So even if I make the prevKey null and pass in a key mapping for the lazy column, I get the same results
You can see the list itself has repeated data:
Copy code
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: He was funny and kind
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: instant karma from a squirrel
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Jerry Springer is a tough SOB
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Hmmm, im seeing a pattern
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: "Dont get me what i asked for"
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: He was funny and kind
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: instant karma from a squirrel
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Jerry Springer is a tough SOB
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Hmmm, im seeing a pattern
2021-09-16 21:28:26.556 23852-23852/com.bohregard.pagertest D/DEBUG: Post: "Dont get me what i asked for"
Which prevents me from using the key mapping since the keys will end up being duplicated
As more items are loaded, it just evicts earlier items:
Copy code
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: To call out a racist
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Pickles likes tuna more than the raccoons apparently.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Pretty sure this counts.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Rate my setup.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: When you drove into a strange area and a fight started 🙈😳😅
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: To call out a racist
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Pickles likes tuna more than the raccoons apparently.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Pretty sure this counts.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Rate my setup.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: When you drove into a strange area and a fight started 🙈😳😅
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: To call out a racist
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Pickles likes tuna more than the raccoons apparently.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Pretty sure this counts.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: Rate my setup.
2021-09-16 21:28:26.789 23852-23852/com.bohregard.pagertest D/DEBUG: Post: When you drove into a strange area and a fight started 🙈😳😅
java.lang.IllegalArgumentException: Key ppkbl0 was already used. If you are using LazyColumn/Row please make sure you provide a unique key for each item.
d
how do you determine what is the last page? if you get an empty response, make sure to pass null for nextKey as well to tell paging there's no more to load on that direction
thats probably why you're hitting that error after setting prevKey to null
d
Okay I just opened up your project
Your TypeAdapter for the api response returns a mutable list which you re-use across different calls
that's why the first page is getting repeated, when you add the posts from the second response, you are also modifying the list for the first page
Copy code
return PostResponse(after, posts.toList())
making a deep copy like this solves your issue
btw, there is technically a finite number of reddit posts, even though r/all probably goes on for a very long time - I would still try an obscure search on a less popular subreddit and see what their terminal behavior looks like so you can account for that
which will be useful to you if you ever add support for search / different subreddits
actually I would also recommend to just use something like moshi or gson so you don't have to write typeadapters yourself for the most part
b
🤦‍♂️
Yeah that definitely fixes it. I’m not even sure why I have it written like that. FWIW, I am using moshi but I need the type adapter for this piece. In re the less popular subreddits, you are right. I’ll look into that now that this works. I appreciate the help!