TMDB应用Room离线功能实现中Remote Mediator仅加载第一页的问题修复咨询
修复RemoteMediator加载多页数据的问题
咱们先梳理下你当前代码里导致只能加载第一页的几个核心问题,然后直接上修改后的代码并解释每个改动点:
问题分析
- APPEND阶段的loadKey计算逻辑错误:你现在在APPEND时尝试从数据库拿整个MoviesPage对象,但没有从中提取出下一页的页码,反而直接返回这个对象作为loadKey,完全不符合Paging3的要求(loadKey应该是下一页的页码数值)。
- API请求的page参数传错了:调用
service.getPopular时,你传的是state.config.pageSize(每页条数),但API需要的是页码数值,这直接导致你每次都在请求错误的页。 - 页面状态的更新逻辑不完整:刷新(REFRESH)时没有清除旧的页面数据,可能导致后续页码计算混乱;同时没有正确记录当前已加载的最大页码。
修改后的完整代码
@OptIn(ExperimentalPagingApi::class) class MoviesPopularMediator( private val service: ApiService, private val database: PopularMoviesDatabase ) : RemoteMediator<Int, MoviesModel>() { override suspend fun load( loadType: LoadType, state: PagingState<Int, MoviesModel> ): MediatorResult { return try { // 计算要加载的页码 val loadKey = when (loadType) { LoadType.REFRESH -> 1 LoadType.PREPEND -> { // 加载前面的页,这里不需要,直接返回结束 return MediatorResult.Success(endOfPaginationReached = true) } LoadType.APPEND -> { // 获取数据库中已保存的最后一页页码,加1就是下一页 val lastPage = database.popularMoviesPageDao().getLastPageNumber() // 如果没有找到最后一页,说明还没加载过,直接返回结束 lastPage?.plus(1) ?: return MediatorResult.Success(endOfPaginationReached = true) } } // 调用API请求对应页码的数据 val response = service.getPopular(page = loadKey) val listing = response.body() ?: return MediatorResult.Success(endOfPaginationReached = true) database.withTransaction { if (loadType == LoadType.REFRESH) { // 刷新时清空旧数据,避免重复 database.popularMoviesDao().clearAll() database.popularMoviesPageDao().clearAll() } // 保存当前页的页码信息 database.popularMoviesPageDao().savePopularMoviesPage( MoviesPage( page = listing.page, results = listing.results, total_pages = listing.total_pages ) ) // 保存当前页的电影数据 database.popularMoviesDao().savePopularMovies(listing.results) } // 判断是否已经加载完所有页:当前页等于总页数时,结束分页 val endOfPagination = listing.page == listing.total_pages MediatorResult.Success(endOfPaginationReached = endOfPagination) } catch (exception: IOException) { MediatorResult.Error(exception) } catch (exception: HttpException) { MediatorResult.Error(exception) } } } // 给你的PopularMoviesPageDao添加两个方法: // 1. 获取最后一页的页码 @Query("SELECT MAX(page) FROM popular_movies_page") suspend fun getLastPageNumber(): Int? // 2. 清空页面记录(刷新时用) @Query("DELETE FROM popular_movies_page") suspend fun clearAll()
关键改动说明
- 修正APPEND的loadKey计算:现在通过
getLastPageNumber()从数据库获取已加载的最大页码,加1作为下一页的请求key,符合Paging3的分页逻辑。 - 修正API请求的page参数:把之前错误的
state.config.pageSize改成了正确的loadKey,这样每次请求的都是对应页码的数据。 - 添加刷新时的清空逻辑:刷新(REFRESH)时清空数据库里的旧数据和页面记录,避免数据重复和页码计算错误。
- 优化分页结束判断:直接用API返回的
listing.page和listing.total_pages对比,准确判断是否已经加载完所有页面。
另外,记得确保你的PopularMoviesPageDao添加了上面标注的两个新方法,这样才能正确获取最后一页页码和清空旧数据。
内容的提问来源于stack exchange,提问作者t3nsa
相关产品推荐
相关产品推荐

