I'm having a problem with refreshing the paged data and I'm not sure how I need to set the refresh key so it works correctly. The docs aren't clear at all. I have this base class for offset paging, so it goes 0-40, 40-60, 60-80, and so on. And that works, but when I'm in the middle of the collection and I want to refresh the data, either with invalidate() or adapter.refresh(), it crashes with following message:
java.lang.IllegalStateException: The same value, 40, was passed as the prevKey in two sequential Pages loaded from a PagingSource. Re-using load keys in PagingSource is often an error, and must be explicitly enabled by overriding PagingSource.keyReuseSupported.
When it is enabled, it doesn't crash, but its behavior is weird because it starts paging from the middle and I can't go back to the beginning of the collection, as it is constantly paging the same items.
Example:
prevKey null, nextKey: 40 -> prevKey 40, nextKey: 60 -> prevKey 60, nextKey: 80
Invalidate()
prevKey 40, nextKey: 80 -> prevKey 40, nextKey: 60 // This is the case when it crashes without the keyReuseSupported flag.
And as I want to go back to the beginning it is stuck on prevKey 40, nextKey: 60
abstract class OffsetPagingSource<Value : Any>(
private val coroutineScope: CoroutineScope
) : PagingSource<Int, Value>() {
abstract suspend fun queryFactory(
size: Int,
after: Int,
itemCount: Boolean
): PagingResult<Value>?
abstract suspend fun subscriptionFactory(): Flow<Any>?
init {
initSubscription()
}
private fun initSubscription() {
coroutineScope.launch {
try {
subscriptionFactory()?.collect {
invalidate()
}
} catch (e: Throwable) {}
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Value> {
val size = params.loadSize
val after = params.key ?: 0
return try {
val result = queryFactory(size, after, true) ?: return LoadResult.Page(emptyList(), null, null)
val totalCount = result.pageInfo.itemCount
val nextCount = after + size
val prevKey = if (after == 0) null else after
val nextKey = if (nextCount < totalCount) nextCount else null
LoadResult.Page(result.edges.mapNotNull { it.node }, prevKey = prevKey, nextKey)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, Value>): Int? {
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey
}
}
}
Does anyone know how to fix this? I'm not sure if this is a bug or not. Paging 3 kinds of forces a way the paging works and not enabling a different approach.