[英]Android: Paging3 create remotemediator with cloud-firestore
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.我正在尝试使用 Paging3 创建一个 RemoteMediator,我在其中缓存本地结果以节省网络流量、云火存储文档访问并计算每个查询的项目数量以显示占位符。
I've already successfully implemented the "only network way" by implementing a pagingsource that access my cloud-firestore and loads the nextpage.我已经通过实现访问我的 cloud-firestore 并加载下一页的分页源成功地实现了“唯一的网络方式”。 But I am struggling with the RemoteMediator way, because there are zero tutorials how to do this in combination with cloud-firestore.但我正在努力使用 RemoteMediator 方式,因为如何结合 cloud-firestore 做到这一点的教程为零。
I will provide my current approach (pagingSource way) and how far I got with my RemoteMediator.我将提供我当前的方法(pagingSource 方式)以及我的 RemoteMediator 走了多远。 I appreciate any help.我很感激任何帮助。
@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)
}
}
}
@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
)
}
}
There's many problems with your implementation, first of all, repository shouldn't be injected into data source, it should be backward and create an injected instance of the dataSource into repository with a function that provides data from dataSource with proper configuration, the correct flow involves to pull paginated data from dataSource who pulls the data from database, then when data is over, the dataSource should ask for more data to the remoteMediator, who is in charge of refresh, append or preppend data from a network source based on the type of request the dataSource is asking for, finally your repository should be injected into useCases for each function that provides de data (flow, liveData RxJava, an so...) to the UI and work with it in a recyclerView or lazyColumn(If you're using compose).您的实现存在很多问题,首先,存储库不应该注入数据源,它应该是向后的,并使用 function 将数据源的注入实例创建到存储库中,该 function 提供来自具有正确配置的数据源的数据,正确的流程涉及到从dataSource拉分页数据,从dataSource拉取数据,当数据结束时,dataSource应该向remoteMediator请求更多数据,remoteMediator负责刷新,append或根据类型从网络源中添加数据数据源请求的请求,最后你的存储库应该被注入到每个 function 的用例中,这些 function 向 UI 提供数据(流,liveData RxJava,等等......)并在 recyclerView 或lazyColumn 中使用它(如果你'正在使用撰写)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.