android paging使用教程
以下是基于最新 Paging3 的 Android 分页库使用教程,结合官方文档和开发者实践总结:
一、基础配置
添加依赖
// build.gradle
dependencies {
def paging_version = "3.2.1"
implementation "androidx.paging:paging-runtime:$paging_version"
implementation "androidx.paging:paging-compose:$paging_version" // Compose 支持
testImplementation "androidx.paging:paging-testing:$paging_version"
}
核心组件
PagingSource:定义数据加载逻辑
Pager:配置分页参数并生成 PagingData 流
PagingDataAdapter:适配 RecyclerView 或 Compose 列表
RemoteMediator(可选):处理网络+本地缓存的分页协调
二、基础分页实现(纯网络请求)
创建 PagingSource
class ArticlePagingSource(private val api: ApiService) : PagingSource<Int, Article>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Article> {
return try {
val page = params.key ?: 1
val response = api.getArticles(page)
LoadResult.Page(
data = response.articles,
prevKey = if (page > 1) page - 1 else null,
nextKey = if (response.hasMore) page + 1 else null
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
ViewModel 中配置 Pager
class ArticleViewModel : ViewModel() {
private val api = RetrofitClient.apiService
val articles = Pager(
config = PagingConfig(
pageSize = 20,
enablePlaceholders = false,
initialLoadSize = 40
),
pagingSourceFactory = { ArticlePagingSource(api) }
).flow.cachedIn(viewModelScope)
}
UI 层实现(RecyclerView)
// Adapter
class ArticleAdapter : PagingDataAdapter<Article, ArticleViewHolder>(DIFF_CALLBACK) {
companion object {
val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Article>() {
override fun areItemsTheSame(oldItem: Article, newItem: Article) =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Article, newItem: Article) =
oldItem == newItem
}
}
}
// Activity/Fragment
lifecycleScope.launch {
viewModel.articles.collectLatest { pagingData ->
adapter.submitData(pagingData)
}
}
三、进阶场景(网络+数据库)
使用 RemoteMediator
@ExperimentalPagingApi
class ArticleRemoteMediator(
private val db: AppDatabase,
private val api: ApiService
) : RemoteMediator<Int, Article>() {
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Article>
): MediatorResult {
// 实现网络请求与数据库缓存的协调逻辑
// 详见官方示例:https://github.com/android/architecture-components-samples/tree/main/PagingWithNetworkSample
}
}
Room 集成
@Dao
interface ArticleDao {
@Query("SELECT * FROM articles ORDER BY timestamp DESC")
fun articlesPagingSource(): PagingSource<Int, Article>
}
// 创建 Pager 时组合 RemoteMediator
Pager(
config = PagingConfig(pageSize = 20),
remoteMediator = ArticleRemoteMediator(db, api),
pagingSourceFactory = { db.articleDao().articlesPagingSource() }
)
四、状态监听与 UI 反馈
// 监听加载状态
adapter.addLoadStateListener { loadState ->
when (loadState.refresh) {
is LoadState.Loading -> showLoading()
is LoadState.NotLoading -> hideLoading()
is LoadState.Error -> showError()
}
}
// 错误重试
binding.retryButton.setOnClickListener {
adapter.retry()
}
五、最佳实践建议
性能优化
使用 cachedIn() 缓存数据流
合理设置 PagingConfig 参数(prefetchDistance 等)
实现高效的 DiffUtil 对比逻辑
测试策略
使用 TestPager 和 TestDispatcher 进行单元测试
验证边界条件(空列表、单页数据、加载错误等)
架构整合
配合 ViewModel + LiveData/Flow 使用
通过 Hilt/Dagger 实现依赖注入
结合 SwipeRefreshLayout 实现下拉刷新
完整实现示例可参考 Google 官方示例仓库 ,或通过 查看实际项目集成方式。