如何在现有架构中使用Paging Library 3实现Jetpack Compose分页功能
Jetpack Compose 集成 Paging 3 实现分页步骤
1. 添加依赖
首先在模块级build.gradle中添加Paging3相关依赖:
dependencies { // Paging 3 核心依赖 implementation "androidx.paging:paging-runtime-ktx:3.2.1" // Compose 适配依赖 implementation "androidx.paging:paging-compose:3.2.1" }
2. 改造网络请求接口
首先需要你的后端接口支持分页传参,通常需要传入页码page、每页条数pageSize,对应改造Services接口:
// 示例改造搜索接口,根据你后端实际参数调整 @GET("category/busca/{title}") suspend fun getSearch( @Path("title") title: String, @Query("page") page: Int, @Query("pageSize") pageSize: Int ): List<ShoppingCart>
3. 实现PagingSource
自定义PagingSource处理分页加载逻辑:
class SearchPagingSource( private val repository: SearchRepository, private val searchKeyword: String ) : PagingSource<Int, ShoppingCart>() { override suspend fun load(params: LoadParams<Int>): LoadResult<Int, ShoppingCart> { return try { // 当前页码,首次加载为null,默认取第1页 val currentPage = params.key ?: 1 // 请求数据 val data = repository.getSearch(searchKeyword, currentPage, params.loadSize) // 计算前后页页码,逻辑根据你后端返回规则调整 val prevPage = if (currentPage > 1) currentPage -1 else null val nextPage = if (data.isNotEmpty()) currentPage +1 else null LoadResult.Page( data = data, prevKey = prevPage, nextKey = nextPage ) } catch (e: Exception) { LoadResult.Error(e) } } override fun getRefreshKey(state: PagingState<Int, ShoppingCart>): Int? { // 刷新时用的key,可直接返回null或者取最近访问的页码 return state.anchorPosition?.let { anchorPosition -> state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1) ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1) } } }
4. 改造Repository层
修改SearchRepository,新增返回PagingData的方法:
class SearchRepository { private val retrofit = Retrofit() private val search = retrofit.frutasServices // 原有方法保留,新增分页请求方法 suspend fun getSearch(keyword: String, page: Int, pageSize: Int) = search.getSearch(keyword, page, pageSize) // 提供分页数据流 fun getSearchPagingFlow(keyword: String): Flow<PagingData<ShoppingCart>> { return Pager( config = PagingConfig( pageSize = 10, // 每页加载条数,按需调整 enablePlaceholders = false, initialLoadSize = 10 // 首次加载条数 ), pagingSourceFactory = { SearchPagingSource(this, keyword) } ).flow } }
5. 改造ViewModel层
修改SearchViewModel,直接暴露PagingData流,无需自己维护列表状态:
class SearchViewModel: ViewModel() { private val searchRepository = SearchRepository() // 搜索结果分页流 val searchPagingFlow: MutableStateFlow<Flow<PagingData<ShoppingCart>>?> = MutableStateFlow(null) fun buscar(title: String) { searchPagingFlow.value = searchRepository.getSearchPagingFlow(title) .cachedIn(viewModelScope) // 绑定ViewModel生命周期,页面重建不用重新请求 } }
6. Compose UI层渲染分页列表
在Composable中收集PagingData,用LazyPagingItems渲染列表,同时可以处理加载中、加载失败、空列表等状态:
@Composable fun SearchListScreen(viewModel: SearchViewModel = viewModel()) { // 触发搜索 LaunchedEffect(Unit) { viewModel.buscar("你的搜索关键词") } val pagingFlow = viewModel.searchPagingFlow.collectAsStateWithLifecycle().value pagingFlow?.let { flow -> val lazyPagingItems = flow.collectAsLazyPagingItems() LazyColumn { items(lazyPagingItems) { item -> // 你的列表Item布局 item?.let { ShoppingCartItem(it) } } // 处理列表加载状态 lazyPagingItems.apply { when { loadState.refresh is LoadState.Loading -> { // 首次加载loading item { LoadingItem() } } loadState.refresh is LoadState.Error -> { // 首次加载失败 val error = loadState.refresh as LoadState.Error item { ErrorItem(error.error.message ?: "加载失败") { retry() } } } loadState.append is LoadState.Loading -> { // 加载下一页loading item { AppendLoadingItem() } } loadState.append is LoadState.Error -> { // 加载下一页失败 val error = loadState.append as LoadState.Error item { AppendErrorItem(error.error.message ?: "加载更多失败") { retry() } } } } } } } }
注意:如果你的后端分页参数规则、返回结构和示例不同,需要对应调整
PagingSource中的页码计算、下一页判断逻辑。
内容的提问来源于stack exchange,提问作者Rafael Souza
相关产品推荐
相关产品推荐

