You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

服务器无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,提问作者송규빈

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 19:59:59