在 Compose 列表中实现分页
使用 LazyColumn 渲染分页数据
在 Compose 列表中实现分页 是 CoddyKit 上的免费 Android Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 4 节课。
在 Compose 中呈现分页数据
数据层会提供一个 Flow<PagingData<Article>>。paging-compose 库会将这个数据流转换为 LazyColumn 可以呈现的对象,并在用户滚动时按需加载数据。
其中的关键桥接函数是 collectAsLazyPagingItems()。
collectAsLazyPagingItems
在可组合函数中对数据流调用 collectAsLazyPagingItems()。它会返回一个 LazyPagingItems 对象,用于跟踪已加载的项目和加载状态,并在页面到达时重新组合界面。
import androidx.paging.compose.collectAsLazyPagingItems
@Composable
fun ArticleScreen(viewModel: ArticleViewModel) {
val articles = viewModel.articles.collectAsLazyPagingItems()
ArticleList(articles)
}使用 LazyPagingItems 调用 items()
在 LazyColumn 中使用 Paging 的 items() 重载。它会从 LazyPagingItems 读取数据,并在用户接近列表末尾时触发下一页的加载。
启用占位符后,每个项目都可能是 null,因此请处理这种情况。
import androidx.compose.foundation.lazy.LazyColumn
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.items
@Composable
fun ArticleList(articles: LazyPagingItems<Article>) {
LazyColumn {
items(articles) { article ->
if (article != null) {
ArticleRow(article)
}
}
}
}为项目设置稳定键
为每一行提供稳定键,以便 Compose 在页面加载过程中高效跟踪项目,并避免不必要的重新组合。
请使用 Paging 的 itemKey 辅助工具,并传入项目 ID 之类唯一且稳定的属性。
import androidx.paging.compose.itemKey
LazyColumn {
items(
count = articles.itemCount,
key = articles.itemKey { it.id }
) { index ->
val article = articles[index]
if (article != null) ArticleRow(article)
}
}读取加载状态
LazyPagingItems.loadState 会公开以下三种操作当前的加载状态和错误状态:
refresh- 初始加载或下拉刷新加载append- 加载下一页(向下滚动)prepend- 加载上一页(向上滚动)
import androidx.paging.LoadState
val refresh = articles.loadState.refresh
val append = articles.loadState.append
val isInitialLoading = refresh is LoadState.Loading
val isLoadingMore = append is LoadState.Loading全屏加载状态和空状态
使用 refresh 状态来控制初始界面:加载时显示居中的加载动画,失败时显示错误界面,没有可显示内容时显示空状态消息。
when (val refresh = articles.loadState.refresh) {
is LoadState.Loading -> FullScreenSpinner()
is LoadState.Error -> FullScreenError(
message = refresh.error.message,
onRetry = { articles.retry() }
)
is LoadState.NotLoading -> {
if (articles.itemCount == 0) EmptyState()
else ArticleList(articles)
}
}追加数据时显示底部加载动画
要在加载下一页时于底部显示小型加载动画,请根据 append 加载状态向 LazyColumn 添加一个额外项目。
LazyColumn {
items(count = articles.itemCount, key = articles.itemKey { it.id }) { index ->
articles[index]?.let { ArticleRow(it) }
}
if (articles.loadState.append is LoadState.Loading) {
item {
Box(Modifier.fillMaxWidth().padding(16.dp), Alignment.Center) {
CircularProgressIndicator()
}
}
}
}发生错误时重试
追加数据失败时,请在底部显示重试行。调用 articles.retry() 只会重新尝试失败的加载,不会重新加载整个列表。
val append = articles.loadState.append
if (append is LoadState.Error) {
item {
Row(Modifier.fillMaxWidth().padding(16.dp), Arrangement.Center) {
Text("Couldn't load more")
Spacer(Modifier.width(8.dp))
Button(onClick = { articles.retry() }) { Text("Retry") }
}
}
}下拉刷新
使用 articles.refresh() 触发全新加载。可以将它与 Material 3 的下拉刷新结合使用,并根据 refresh 加载状态控制指示器。
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
val isRefreshing = articles.loadState.refresh is LoadState.Loading
PullToRefreshBox(
isRefreshing = isRefreshing,
onRefresh = { articles.refresh() }
) {
ArticleList(articles)
}页眉与分隔线
您可以在同一个 LazyColumn 中自由混合分页项目和非分页内容。在分页 items() 调用周围添加粘性页眉、搜索栏或分区分隔线。
由于所有内容都位于同一个 LazyColumn 中,滚动会保持统一且流畅。
LazyColumn {
item { SearchBar(query, onQueryChange) }
items(count = articles.itemCount, key = articles.itemKey { it.id }) { index ->
val article = articles[index]
if (article != null) {
ArticleRow(article)
HorizontalDivider()
}
}
if (articles.loadState.append.endOfPaginationReached) {
item { Text("You're all caught up", Modifier.padding(16.dp)) }
}
}预览分页列表
对于 Compose 预览和测试,不需要真实的网络。请将示例数据包装在 PagingData.from(...) 中,并将其公开为数据流。
这样,您就可以独立构建和预览列表界面。
import androidx.paging.PagingData
import kotlinx.coroutines.flow.flowOf
@Preview
@Composable
fun ArticleListPreview() {
val sample = listOf(Article(1, "Hello"), Article(2, "World"))
val flow = flowOf(PagingData.from(sample))
ArticleList(flow.collectAsLazyPagingItems())
}快速检查
哪个函数可以将 Flow<PagingData> 转换为 Compose LazyColumn 能够呈现的对象?
回顾:Compose 中的分页
您已经在 Jetpack Compose 中呈现了分页数据:
collectAsLazyPagingItems()将数据流连接到界面- Paging 的
items()重载会在滚动时加载更多数据;请处理null占位项目 - 使用
itemKey { it.id }设置稳定键 loadState.refresh/append/prepend用于控制加载动画、错误状态和空状态retry()和refresh()用于从失败中恢复并重新加载
下一步:使用 RemoteMediator 结合网络和数据库。
常见问题解答
「在 Compose 列表中实现分页」课时是免费的吗?
是的 — 「在 Compose 列表中实现分页」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 4 节课。
「在 Compose 列表中实现分页」这节课中我会学到什么?
使用 LazyColumn 渲染分页数据 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Android Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「在 Compose 列表中实现分页」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Android Academy 课中编写并运行代码吗?
能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 为什么需要分页
- PagingSource 与 Pager
- 在 Compose 列表中实现分页
- RemoteMediator 与缓存