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

Android Jetpack Paging3如何切换参数重新加载分页数据?

问题根源

你的核心问题在于PagingSource是一次性绑定参数的实例,切换分类后没有触发新的PagingSource创建,调用refresh()只会复用旧的PagingSource(持有旧参数),自然加载不到新分类的数据。要解决这个问题,必须让参数变化时重新生成PagingSource,并让UI订阅新的分页数据流。

分步解决方案

1. 改造PagingSource:让它绑定动态参数

修改MoviePagingSource,将分类参数(如mediaType)作为构造参数传入,确保每次加载都使用当前参数:

class MoviePagingSource(
    private val api: MovieApi,
    private val mediaType: String // 新增:区分电影/剧集的参数
) : PagingSource<Int, Movie>() {

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movie> {
        val currentPage = params.key ?: 1
        return try {
            // 用构造传入的参数调用API
            val response = api.getMovies(mediaType, currentPage)
            LoadResult.Page(
                data = response.results,
                prevKey = if (currentPage == 1) null else currentPage - 1,
                nextKey = if (response.results.isEmpty()) null else currentPage + 1
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }

    // 可选:重写getRefreshKey,确保刷新时回到第一页
    override fun getRefreshKey(state: PagingState<Int, Movie>): Int? {
        return 1
    }
}

2. 改造Repository:根据参数生成新的分页数据流

让Repository提供根据参数创建Pager的方法,确保每次调用都生成新的PagingSource实例:

class MovieRepository(private val api: MovieApi) {
    fun getMoviePagingData(mediaType: String): Flow<PagingData<Movie>> {
        return Pager(
            config = PagingConfig(
                pageSize = 20,
                enablePlaceholders = false
            ),
            // 每次调用都创建新的PagingSource,绑定当前参数
            pagingSourceFactory = { MoviePagingSource(api, mediaType) }
        ).flow
    }
}

3. 改造ViewModel:用StateFlow驱动参数变化,自动切换数据流

通过MutableStateFlow保存当前分类参数,用flatMapLatest监听参数变化,自动生成新的分页数据流:

class MovieViewModel(private val repo: MovieRepository) : ViewModel() {
    // 保存当前选中的分类,默认是电影
    private val _currentMediaType = MutableStateFlow("movie")
    val currentMediaType = _currentMediaType.asStateFlow()

    // 监听分类变化,自动切换分页数据流
    val pagingDataFlow = currentMediaType.flatMapLatest { type ->
        repo.getMoviePagingData(type)
    }.cachedIn(viewModelScope) // 缓存数据流,避免配置变化时重复请求

    // 对外暴露的分类切换方法
    fun switchMediaType(newType: String) {
        if (_currentMediaType.value != newType) {
            _currentMediaType.value = newType
        }
    }
}

4. 改造Activity:绑定按钮点击,订阅数据流

点击按钮时只需更新ViewModel的分类参数,订阅的数据流会自动推送新的分页数据:

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MovieViewModel
    private lateinit var adapter: MovieAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProvider(this)[MovieViewModel::class.java]
        adapter = MovieAdapter()
        recyclerView.adapter = adapter

        // 订阅分页数据流,自动更新列表
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.pagingDataFlow.collect { pagingData ->
                    adapter.submitData(pagingData)
                }
            }
        }

        // 电影按钮点击
        btnMovie.setOnClickListener {
            viewModel.switchMediaType("movie")
            // 可选:强制立即刷新(一般不需要,数据流切换后会自动加载第一页)
            // adapter.refresh()
        }

        // 剧集按钮点击
        btnTv.setOnClickListener {
            viewModel.switchMediaType("tv")
            // adapter.refresh()
        }
    }
}
关键说明
  • 为什么这样有效:每次分类变化时,flatMapLatest会取消旧的分页数据流,重新调用repo.getMoviePagingData()生成新的Pager和PagingSource,新的PagingSource持有最新的分类参数,自然会加载对应数据并重置到第一页。
  • cachedIn的作用:将分页数据流缓存到ViewModel的作用域中,屏幕旋转等配置变化时,不会重新发起请求,保留当前分页状态。
  • 避免手动调用refresh():只要参数变化触发了新的数据流生成,submitData()会自动让adapter重置并加载第一页,无需额外调用refresh()。

内容的提问来源于stack exchange,提问作者Saneen K P

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 23:25:25