我正在尝试创建一个带有Paging3的RemoteMediator,在那里我缓存本地结果,以节省网络流量、云存储文档访问,并计算每个查询的项目数量,以显示占位符。
我已经成功地实现了";唯一网络方式";通过实现一个分页源来访问我的cloudfirestore并加载下一页。但我很难用RemoteMediator的方式,因为没有任何教程可以结合cloudfirestore来实现这一点。
我将提供我目前的方法(分页源方式(以及我使用RemoteMediator的进展。我感谢你的帮助。
存储库
@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()
}
当前方法(工作(
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方法(无线索(
@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
)
}
}
您的实现有很多问题,首先,存储库不应该注入到数据源中,它应该向后创建一个注入到存储库中的dataSource实例,该实例具有一个功能,该功能通过适当的配置从dataSource提供数据,正确的流程包括从dataSource中提取分页数据,那么当数据结束时,dataSource应该向remoteMediator请求更多数据,remoteMediator负责根据dataSource请求的类型刷新、附加或预挂起来自网络源的数据,最后,您的存储库应该被注入到为UI提供反数据(flow、liveData RxJava、an so…(的每个函数的用例中,并在recyclerView或lazyColumn中使用它(如果您使用compose(。