服务器无ID与分页值时,如何使用RemoteMediator?
解决方案
1. 调整RemoteKey实体为全局单一记录
因为你的列表是全局分页(而非按分组分页),不需要为每个Item分配RemoteKey,只需用固定值作为唯一主键来维护一组分页键即可:
@Entity(tableName = "remote_keys") data class RemoteKey( // 用固定值作为全局唯一主键,比如0或字符串常量 @PrimaryKey val id: Int = 0, val prevKey: Int?, val nextKey: Int?, val isEnd: Boolean? )
2. 解决Item无唯一ID的问题
本地数据库的Item实体使用自增主键,由Room自动生成唯一标识:
@Entity(tableName = "items") data class ItemEntity( @PrimaryKey(autoGenerate = true) val localId: Long = 0, val collection: String?, val imageUrl: String?, val datetime: String? )
3. 修改RemoteMediator事务逻辑
不再依赖item.id,直接插入/替换全局RemoteKey记录,同时处理分页逻辑:
database.withTransaction { if (loadType == LoadType.REFRESH) { database.remoteKeysDao().clearRemoteKeys() database.itemsDao().clearItems() } // 计算下一页页码:未到末尾则当前page+1,否则为null val nextKey = if (response.info?.isEnd == false) page + 1 else null // 插入/替换全局RemoteKey database.remoteKeysDao().insertOrReplace(RemoteKey( id = 0, prevKey = if (page > 0) page - 1 else null, nextKey = nextKey, isEnd = response.info?.isEnd )) // 将服务器响应映射为本地实体后插入 val localItems = response.items?.map { ItemEntity( collection = it.collection, imageUrl = it.imageUrl, datetime = it.datetime ) } ?: emptyList() database.itemsDao().insertAll(localItems) }
4. 补充RemoteKeysDao方法
添加插入替换和获取全局RemoteKey的方法:
@Dao interface RemoteKeysDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertOrReplace(remoteKey: RemoteKey) @Query("SELECT * FROM remote_keys WHERE id = 0") suspend fun getGlobalRemoteKey(): RemoteKey? @Query("DELETE FROM remote_keys") suspend fun clearRemoteKeys() }
5. RemoteMediator中获取分页键
在load方法中,通过全局RemoteKey获取下一页/上一页的页码:
override suspend fun load( loadType: LoadType, state: PagingState<Int, ItemEntity> ): MediatorResult { val page = when (loadType) { LoadType.REFRESH -> 0 LoadType.PREPEND -> { val remoteKey = database.remoteKeysDao().getGlobalRemoteKey() remoteKey?.prevKey ?: return MediatorResult.Success(endOfPaginationReached = true) } LoadType.APPEND -> { val remoteKey = database.remoteKeysDao().getGlobalRemoteKey() remoteKey?.nextKey ?: return MediatorResult.Success(endOfPaginationReached = true) } } // 发起网络请求,传入page参数 return try { val response = api.getItems(page = page) // 执行上述事务逻辑 MediatorResult.Success(endOfPaginationReached = response.info?.isEnd == true) } catch (e: Exception) { MediatorResult.Error(e) } }
内容的提问来源于stack exchange,提问作者송규빈
相关产品推荐
相关产品推荐

