This is my attempt at paginating a collection of Firestore chat messages with Paging 3. It correctly loads the next pages, so the startAfter
operator seems to be working as expected. But it's not loading previous pages correctly. Instead, it always loads the very first page again and appends it at the beginning of the list. (I start dropping pages after 100 items so lazy loading works in both directions).
The prevKey
seems to be passed correctly. It has the correct value at beginning of the load method right before we build the query.
timeStamp
is a Firestore server timestamp annotated with @ServerTimestamp
if that matters.
class ChatMessagesPagingSource(
private val messageCollection: CollectionReference
) : PagingSource<ChatMessagesPagingSource.PagingKey, ChatMessage>() {
override suspend fun load(params: LoadParams<PagingKey>): LoadResult<PagingKey, ChatMessage> {
return try {
var query = messageCollection
.orderBy("timeStamp", Query.Direction.DESCENDING)
.limit(params.loadSize.toLong())
val key = params.key
Timber.d("key = $key")
query = when (key) {
is PagingKey.PreviousKey -> query.endBefore(key.endBefore)
is PagingKey.NextKey -> query.startAfter(key.startAfter)
null -> query
}
val querySnapshot = query.get().await()
val chatMessages = querySnapshot.toObjects(ChatMessage::class.java)
val firstDoc = querySnapshot.documents.firstOrNull()
val lastDoc = querySnapshot.documents.lastOrNull()
val prevKey = if (firstDoc != null) PagingKey.PreviousKey(firstDoc) else null
val nextKey = if (lastDoc != null) PagingKey.NextKey(lastDoc) else null
Timber.d("first message: ${chatMessages.firstOrNull()}")
Timber.d("last message: ${chatMessages.lastOrNull()}")
LoadResult.Page(
data = chatMessages,
prevKey = prevKey,
nextKey = nextKey
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
sealed class PagingKey{
data class PreviousKey(val endBefore: DocumentSnapshot) : PagingKey()
data class NextKey(val startAfter: DocumentSnapshot) : PagingKey()
}
}
You need to check for the type of LoadParams, to see if it is refresh, prepend or append.
Since your query always fetches items after in descending order, when it requests a prepend you're probably loading the incorrect items.