Kotlin LazyPagingItems itemCount初始值为0的问题及优化方案问询
LazyPagingItems初始itemCount为0的问题优化方案探讨
在使用Paging3将PagingData收集为LazyPagingItems时,存在一个疑似Bug:LazyPagingItems的itemCount初始值始终为0。如果直接通过该参数控制列表或空状态提示的显示,初始阶段会错误触发空列表分支。
问题代码示例
Box( modifier = Modifier .padding(innerPadding) .nestedScroll(scrollBehavior.nestedScrollConnection) .fillMaxSize() ) { when (val state = homeScreenUiState.homeScreenMovieListState) { is HomeScreenMovieListState.Error -> { LoadingMovieDataImageDisplay( modifier = Modifier.align(Alignment.Center), image = R.drawable.movie_list_loading_error, message = state.message ) } is HomeScreenMovieListState.Loading -> { LoadingMovieDataLoadingDisplay(modifier = Modifier.align(Alignment.Center)) } is HomeScreenMovieListState.Success -> { val movieList = state.movieList.collectAsLazyPagingItems() when { movieList.itemCount > 0 -> { HomeMovieList( movieList = movieList, navigateToMovieDetails = navigateToMovieDetails, lazyGridState = lazyGridState, paddingValues = PaddingValues( top = movieListPaddingValues.value, start = 10.dp, end = 10.dp, bottom = 10.dp, ) ) } movieList.itemCount == 0 -> { LoadingMovieDataImageDisplay( modifier = Modifier.align(Alignment.Center), image = R.drawable.movie_list_loading_error, message = R.string.movie_list_connection_lost, ) } } } } }
临时解决方案
通过添加LoadState检查,避免初始加载时误判为空列表:
when { movieList.itemCount > 0 -> { HomeMovieList( movieList = movieList, navigateToMovieDetails = navigateToMovieDetails, lazyGridState = lazyGridState, paddingValues = PaddingValues( top = movieListPaddingValues.value, start = 10.dp, end = 10.dp, bottom = 10.dp ), ) } movieList.itemCount == 0 && movieList.loadState.refresh != LoadState.Loading -> { LoadingMovieDataImageDisplay( modifier = Modifier.align(Alignment.Center), image = R.drawable.movie_list_loading_error, message = R.string.movie_list_connection_lost, ) } }
更优解决方案探讨
1. 基于LoadState的完整状态流转判断
直接以loadState为核心判断不同状态,逻辑更清晰,避免依赖itemCount的初始值问题:
val movieList = state.movieList.collectAsLazyPagingItems() when { movieList.loadState.refresh is LoadState.Loading -> { // 初始加载中,显示加载组件 LoadingMovieDataLoadingDisplay(modifier = Modifier.align(Alignment.Center)) } movieList.loadState.refresh is LoadState.Error -> { // 初始加载失败,显示错误组件 LoadingMovieDataImageDisplay( modifier = Modifier.align(Alignment.Center), image = R.drawable.movie_list_loading_error, message = (movieList.loadState.refresh as LoadState.Error).error.localizedMessage ) } movieList.itemSnapshotList.isEmpty() -> { // 加载完成且无数据,显示空列表提示 LoadingMovieDataImageDisplay( modifier = Modifier.align(Alignment.Center), image = R.drawable.movie_list_loading_error, message = R.string.movie_list_connection_lost, ) } else -> { // 有数据,显示列表 HomeMovieList( movieList = movieList, navigateToMovieDetails = navigateToMovieDetails, lazyGridState = lazyGridState, paddingValues = PaddingValues( top = movieListPaddingValues.value, start = 10.dp, end = 10.dp, bottom = 10.dp ), ) } }
2. 使用itemSnapshotList替代itemCount
itemSnapshotList是LazyPagingItems当前加载数据的不可变快照,它的isEmpty()能更准确反映实际数据状态,结合加载状态判断更可靠:
val snapshot = movieList.itemSnapshotList if (snapshot.isEmpty() && movieList.loadState.refresh !is LoadState.Loading) { // 显示空列表提示 } else if (movieList.loadState.refresh is LoadState.Loading) { // 显示加载中 } else { // 显示列表 }
3. 封装状态判断扩展函数
将重复的状态判断逻辑抽成扩展函数,提升代码复用性和可读性:
fun <T : Any> LazyPagingItems<T>.isLoading(): Boolean { return loadState.refresh is LoadState.Loading } fun <T : Any> LazyPagingItems<T>.hasError(): Boolean { return loadState.refresh is LoadState.Error } fun <T : Any> LazyPagingItems<T>.isEmptyAfterLoad(): Boolean { return itemSnapshotList.isEmpty() && !isLoading() }
使用时直接调用:
when { movieList.isLoading() -> LoadingMovieDataLoadingDisplay(...) movieList.hasError() -> LoadingMovieDataImageDisplay(...) movieList.isEmptyAfterLoad() -> LoadingMovieDataImageDisplay(...) else -> HomeMovieList(...) }
目前上述临时方案可解决问题,期待Google在Paging3后续版本中修复itemCount初始值的问题。
内容的提问来源于stack exchange,提问作者hbjosemaria
相关产品推荐
相关产品推荐

