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

TMDB应用Room离线功能实现中Remote Mediator仅加载第一页的问题修复咨询

修复RemoteMediator加载多页数据的问题

咱们先梳理下你当前代码里导致只能加载第一页的几个核心问题,然后直接上修改后的代码并解释每个改动点:

问题分析

  1. APPEND阶段的loadKey计算逻辑错误:你现在在APPEND时尝试从数据库拿整个MoviesPage对象,但没有从中提取出下一页的页码,反而直接返回这个对象作为loadKey,完全不符合Paging3的要求(loadKey应该是下一页的页码数值)。
  2. API请求的page参数传错了:调用service.getPopular时,你传的是state.config.pageSize(每页条数),但API需要的是页码数值,这直接导致你每次都在请求错误的页。
  3. 页面状态的更新逻辑不完整:刷新(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()

关键改动说明

  1. 修正APPEND的loadKey计算:现在通过getLastPageNumber()从数据库获取已加载的最大页码,加1作为下一页的请求key,符合Paging3的分页逻辑。
  2. 修正API请求的page参数:把之前错误的state.config.pageSize改成了正确的loadKey,这样每次请求的都是对应页码的数据。
  3. 添加刷新时的清空逻辑:刷新(REFRESH)时清空数据库里的旧数据和页面记录,避免数据重复和页码计算错误。
  4. 优化分页结束判断:直接用API返回的listing.page和listing.total_pages对比,准确判断是否已经加载完所有页面。

另外,记得确保你的PopularMoviesPageDao添加了上面标注的两个新方法,这样才能正确获取最后一页页码和清空旧数据。

内容的提问来源于stack exchange,提问作者t3nsa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 22:07:39