I am trying to create a RemoteMediator with Paging3, where I cache my local results in order to save network traffic, cloud-firestore document access and to count the amount of items per query, to show placeholders.
I've already successfully implemented the "only network way" by implementing a pagingsource that access my cloud-firestore and loads the nextpage. But I am struggling with the RemoteMediator way, because there are zero tutorials how to do this in combination with cloud-firestore.
I will provide my current approach (pagingSource way) and how far I got with my RemoteMediator. I appreciate any help.
Repository
@Singleton
class ShopPagingRepositoryImpl @Inject constructor(private val db: FirebaseFirestore) : ShopPagingRepository {
override suspend fun getCurrentPage(query: QueryHolder): QuerySnapshot = db.collection(FIREBASE_PRODUCTS_BASE_PATH)
.limit(SHOP_DB_DOCUMENT_LIMIT)
.whereEqualTo(FIREBASE_PRODUCT_CATEGORY, query.category)
.orderBy(query.order)
.get()
.await()
override suspend fun getNextPage(lastDocument: DocumentSnapshot, query: QueryHolder): QuerySnapshot = db.collection(FIREBASE_PRODUCTS_BASE_PATH)
.limit(SHOP_DB_DOCUMENT_LIMIT)
.orderBy(query.order, query.direction)
.startAfter(lastDocument)
.whereEqualTo(FIREBASE_PRODUCT_CATEGORY, query.category)
.get()
.await()
}
Current Approach (working)
class ShopPagingSource(
private val shopRepository: ShopPagingRepository,
private val query: QueryHolder
) : PagingSource<QuerySnapshot, Product>() {
private companion object {
const val SHOP_MAX_LOADING_TIME: Long = 5000L
}
override suspend fun load(params: LoadParams<QuerySnapshot>): LoadResult<QuerySnapshot, Product> {
return try {
withTimeout(SHOP_MAX_LOADING_TIME) {
val currentPage = params.key ?: shopRepository.getCurrentPage(query)
val nextPage: QuerySnapshot? = if (currentPage.size() != 0) {
val lastDocumentSnapShot = currentPage.documents[currentPage.size() - 1]
shopRepository.getNextPage(lastDocumentSnapShot, query)
} else null
LoadResult.Page(
data = currentPage.toObjects(),
prevKey = null,
nextKey = nextPage
)
}
} catch (e: Exception) {
Timber.e("Mediator failed, Unknown Error: ${e.message.toString()}")
LoadResult.Error(e)
}
}
}
RemoteMediator approach (no clue)
@ExperimentalPagingApi
class ShopPageMediator(
private val shopRepository: ShopPagingRepository,
private val query: QueryHolder,
private val shopDB: ShopDatabase
): RemoteMediator<QuerySnapshot, Product>() {
private val shopDAO = shopDB.shopDao()
override suspend fun load(
loadType: LoadType,
state: PagingState<QuerySnapshot, Product>,
): MediatorResult {
val loadKey = when(loadType) {
LoadType.REFRESH -> null
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
val lastItem = state.lastItemOrNull() ?: return MediatorResult.Success(endOfPaginationReached = true)
// why lastitem.id, here my lastitem is product. Does this indicate the end of the page?
lastItem.id
}
}
val currentPage = shopRepository.getCurrentPage(
query
)
shopDB.withTransaction {
if (loadType == LoadType.PREPEND) {
// TODO(shopDAO.deleteByQuery(query))
}
shopDAO.insertAll(currentPage.toObjects())
}
val nextPage: QuerySnapshot? = if (currentPage.size() != 0) {
val lastDocumentSnapShot = currentPage.documents[currentPage.size() - 1]
shopRepository.getNextPage(lastDocumentSnapShot, query)
} else null
// Didn't use the result of loadkey anywhere..
return MediatorResult.Success(
endOfPaginationReached = nextPage == null
)
}
}
question from:
https://stackoverflow.com/questions/65599077/android-paging3-create-remotemediator-with-cloud-firestore 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…