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

如何在Compose中使用Paging 3库实现点击按钮加载下一页数据

使用Paging 3实现点击按钮加载下一页电影

要实现用户点击按钮才加载下一页的需求,我们需要修改Paging的自动加载逻辑,改为手动触发。以下是基于你现有代码的改造方案:

1. 修改PagingDataSource,添加手动触发加载的信号

在MoviesPagingDataSource中加入信号流,只有收到手动触发信号时,才会执行下一页加载:

class MoviesPagingDataSource(
    private val repo: MoviesRepository,
    private val loadNextSignal: MutableSharedFlow<Unit> = MutableSharedFlow()
) : PagingSource<Int, Movies>() {

    // 暴露手动触发加载的方法
    suspend fun triggerLoadNext() {
        loadNextSignal.emit(Unit)
    }

    override fun getRefreshKey(state: PagingState<Int, Movies>): Int? {
        return state.anchorPosition?.let { anchorPosition ->
            val anchorPage = state.closestPageToPosition(anchorPosition)
            anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
        }
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movies> {
        return try {
            val nextPageNumber = params.key ?: 0
            // 如果是加载下一页,等待手动触发信号
            if (params is LoadParams.Append) {
                loadNextSignal.first()
            }
            val response = repo.getMovies(page = nextPageNumber, size = 10)
            LoadResult.Page(
                data = response.content,
                prevKey = null,
                nextKey = if (response.content.isNotEmpty()) response.number + 1 else null
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }
}

2. 改造ViewModel,管理加载触发逻辑

在ViewModel中初始化PagingDataSource,并暴露触发加载下一页的方法:

@HiltViewModel
class MoviesViewModel @Inject constructor(
    private val moviesRepository: MoviesRepository
) : ViewModel() {
    private val loadNextSignal = MutableSharedFlow<Unit>()
    private val moviesDataSource = MoviesPagingDataSource(moviesRepository, loadNextSignal)

    // 供UI观察的分页数据流
    val moviesPagingFlow = Pager(PagingConfig(pageSize = 10)) {
        moviesDataSource
    }.flow.cachedIn(viewModelScope)

    // 触发加载下一页
    fun loadNextPage() {
        viewModelScope.launch {
            moviesDataSource.triggerLoadNext()
        }
    }
}

3. 更新UI,替换自动加载为手动按钮

移除原来的自动加载逻辑,改为显示"加载更多"按钮,点击时调用ViewModel的触发方法:

@Composable
fun MoviesList(viewModel: MoviesViewModel) {
    val moviesList = viewModel.moviesPagingFlow.collectAsLazyPagingItems()

    LazyColumn {
        items(moviesList) { item ->
            item?.let { MoviesCard(movie = it) }
        }

        // 加载状态与加载更多按钮
        item {
            when {
                // 正在加载下一页
                moviesList.loadState.append is LoadState.Loading -> {
                    LoadingItem()
                }
                // 加载失败,显示重试按钮
                moviesList.loadState.append is LoadState.Error -> {
                    val error = moviesList.loadState.append as LoadState.Error
                    ErrorItem(message = error.error.message ?: "加载失败") {
                        moviesList.retry()
                    }
                }
                // 还有下一页,显示加载更多按钮
                !moviesList.loadState.append.endOfPaginationReached && moviesList.itemCount > 0 -> {
                    Button(
                        onClick = { viewModel.loadNextPage() },
                        modifier = Modifier.fillMaxWidth().padding(16.dp)
                    ) {
                        Text("加载更多")
                    }
                }
            }
        }

        // 初始刷新状态处理
        when (moviesList.loadState.refresh) {
            is LoadState.Loading -> {
                item {
                    Box(
                        modifier = Modifier.fillMaxSize(),
                        contentAlignment = Alignment.Center
                    ) {
                        CircularProgressIndicator()
                    }
                }
            }
            is LoadState.Error -> {
                item {
                    ErrorItem(message = "加载失败") {
                        moviesList.refresh()
                    }
                }
            }
            else -> Unit
        }
    }
}

核心逻辑说明

  • 通过MutableSharedFlow给PagingDataSource添加阻塞信号,只有UI点击按钮发送信号后,下一页加载才会执行。
  • 保留Paging库的错误重试、状态管理、数据缓存等原生能力,同时完全由用户掌控加载时机。
  • 通过endOfPaginationReached判断是否还有更多数据,自动隐藏加载按钮。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 04:15:39