Jetpack Compose搭配Paging3实现分页时Retrofit无限调用如何解决?
问题成因
- 接口返回参数不匹配
你计算分页边界和下一页页码完全依赖TMDB接口返回的page字段,如果请求的page参数和接口实际返回的page值不一致(比如参数传递错误,请求page=3但接口始终返回page=2),会导致你给当前页所有影片设置的nextKey始终为3,后续APPEND加载时会反复请求同一页,进入死循环。 - 数据库表主键/插入逻辑错误
- RemoteKey表未给
movieId设置唯一约束,同一个影片id会插入多条RemoteKey记录,查询时拿到旧的nextKey,导致重复请求 - Movie表主键配置错误,或者插入影片数据时使用普通insert而非upsert(冲突替换),重复数据插入失败但RemoteKey已写入,导致列表最后一条数据对应的nextKey不会更新,反复触发同页请求
- RemoteKey表未给
- 本地查询排序规则与接口返回不匹配
如果movieDao().pagedTopRated()的查询排序逻辑和TMDB接口返回的排序逻辑不一致,新插入的分页数据会出现在列表头部而非尾部,你取到的列表最后一条数据还是上一页的记录,对应的nextKey还是当前请求的页码,触发重复请求。
排查步骤
- 在RemoteMediator的load方法中添加日志,打印每次请求的page值、接口返回的page、totalPages值,确认请求页码和返回页码是否一致,nextKey是否正常递增。
- 检查数据库表结构:确认RemoteKey表的movieId是唯一主键,Movie表的主键为影片id,插入数据的方法支持冲突时替换旧数据。
- 检查
pagedTopRated方法的查询语句,确认排序规则和TMDB接口返回的排序规则完全一致。
修复方案
- 校验TMDB接口请求参数,确保page参数正确传递,TMDB分页接口的page参数从1开始,和你代码中计算的page值匹配。
- 调整数据库操作逻辑:
- 给RemoteKey表的movieId字段添加唯一约束
- 将
movieDao.insertMovies和movieKeyDao.insertAll改为upsert逻辑,发生主键冲突时直接替换旧记录,示例代码:
@Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertMovies(movies: List<Movie>) @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAll(keys: List<MovieKey>)
- 对齐本地查询和接口返回的排序规则,比如TMDB top rated接口按评分倒序、id升序排列,你的查询语句也要对应添加排序规则:
@Query("SELECT * FROM movie ORDER BY rating DESC, id ASC") fun pagedTopRated(): PagingSource<Int, Movie>
- 添加兜底判断逻辑,拿到请求的page值后,如果page大于接口返回的totalPages,直接返回分页结束:
val response: MovieResponse = networkService.getTopRatedMovies(page) // 新增兜底判断 if (page > response.totalPages) { return MediatorResult.Success(endOfPaginationReached = true) }
内容的提问来源于stack exchange,提问作者Trixy
相关产品推荐
相关产品推荐

