android paging使用教程

发布于:2025-03-09 ⋅ 阅读:(16) ⋅ 点赞:(0)

以下是基于最新 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 官方示例仓库 ,或通过 查看实际项目集成方式。


网站公告

今日签到

点亮在社区的每一天
去签到