Hey everyone, I’m working with the Paging 3 librar...
# compose
k
Hey everyone, I’m working with the Paging 3 library in Jetpack Compose to display a list fetched directly from a server API. It’s important to note that my setup is purely network-based; I am not using a local database or a
RemoteMediator
. The core functionality of loading and displaying pages works perfectly. However, I’m encountering a critical issue when I try to refresh the data after a mutation, like deleting an item. The Scenario: 1. A user scrolls down the list, loading several pages (e.g., they are viewing items on page 3 or 4). 2. The user performs an action that deletes an item from the list. 3. To reflect this change, my UI calls
lazyPagingItems.refresh()
. Instead refresh from initial offset to current offset, I see it triggers from some random offset to till initial offset. you see the sample logs below.
Copy code
2025-08-08 13:17:28.665  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=2000> (857ms)
2025-08-08 13:17:29.507  7055-7265  NetworkLogger           com.example.myapp             D  --> GET <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=1750>
2025-08-08 13:17:30.349  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=1750> (841ms)
2025-08-08 13:17:30.373  7055-7265  NetworkLogger           com.example.myapp             D  --> GET <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=1500>
2025-08-08 13:17:31.264  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=1500> (889ms)
2025-08-08 13:17:31.289  7055-7265  NetworkLogger           com.example.myapp             D  --> GET <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=1250>
2025-08-08 13:17:32.168  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=1250> (878ms)
2025-08-08 13:17:32.194  7055-7265  NetworkLogger           com.example.myapp             D  --> GET <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=1000>
2025-08-08 13:17:33.240  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=1000> (1044ms)
2025-08-08 13:17:33.266  7055-7265  NetworkLogger           com.example.myapp             D  --> GET <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=750>
2025-08-08 13:17:34.290  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=750> (1022ms)
2025-08-08 13:17:34.310  7055-7265  NetworkLogger           com.example.myapp             D  --> GET <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=500>
2025-08-08 13:17:35.151  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=500> (840ms)
2025-08-08 13:17:35.182  7055-7265  NetworkLogger           com.example.myapp             D  --> GET <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=250>
2025-08-08 13:17:36.352  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=250> (1169ms)
2025-08-08 13:17:36.411  7055-7265  NetworkLogger           com.example.myapp             D  --> GET <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=0>
2025-08-08 13:17:37.579  7055-7265  NetworkLogger           com.example.myapp             D  <-- 200 OK <https://api.your-service.com/api/customers?filter=ALL&limit=250&offset=0> (1168ms)
s
Can you share your PagingSource's
override fun getRefreshKey(
function? Two things come to mind that I'm curious about. • Are you correctly determining the anchor position, especially as you receive newly-indexed data which is missing your deleted item? • How are you keying these results from the API? Are you using an index, or a unique ID on each result?
k
here is the getRefreshKey function
Copy code
override fun getRefreshKey(state: PagingState<Int, Any>): Int? {
    return ((state.anchorPosition ?: 0) - state.config.initialLoadSize / 2)
        .coerceAtLeast(0)
}
Key is based on unique ID and DateTime combination for the lazyColumn which is part of the response.
Copy code
key = { index ->
    val item = items.peek(index)
    item.id + item.date + item.dateTime
}