从数据库获取购物列表时圆形加载进度条不显示问题修复
问题修复:加载购物列表时正确显示圆形进度条
问题分析
当前代码存在两个核心问题:
- ViewModel中手动管理的
loading状态逻辑失效:getAllShoppingListItemsUseCase()返回Flow的赋值操作是同步的,导致loading.value = false被立即执行,进度条还未显示就被关闭。 - 空列表提示提前触发:LazyPagingItems的
itemCount在加载过程中可能临时为0,导致加载完成前就显示空文本提示。
解决方案
我们可以直接利用Paging库自带的加载状态管理来替代手动loading变量,同时调整空提示的显示条件,确保仅在加载完成且无数据时才展示。
1. 修改ViewModel:移除手动loading状态
@HiltViewModel class ShoppingListScreenViewModel @Inject constructor( private val getAllShoppingListItemsUseCase: GetAllShoppingListItemsUseCase ) { // 直接暴露Paging Flow,无需包装为State<Flow?> val shoppingListItemsFlow: Flow<PagingData<ShoppingListItem>> = getAllShoppingListItemsUseCase().distinctUntilChanged() }
2. 修改Composable:基于LoadState控制进度条与空提示
fun ShoppingListScreen( navController: NavHostController, shoppingListScreenViewModel: ShoppingListScreenViewModel, sharedViewModel: SharedViewModel ) { val scope = rememberCoroutineScope() val screenHeight = LocalConfiguration.current.screenHeightDp.dp // 直接收集Flow为LazyPagingItems val allItems = shoppingListScreenViewModel.shoppingListItemsFlow.collectAsLazyPagingItems() // 通过Paging的LoadState判断是否处于加载状态 val isLoading = allItems.loadState.refresh is LoadState.Loading Scaffold( topBar = { CustomAppBar( title = "购物列表", titleFontSize = 20.sp, appBarElevation = 4.dp, navController = navController ) }, floatingActionButton = { FloatingActionButton( onClick = { shoppingListScreenViewModel.setStateValue(SHOW_ADD_ITEM_DIALOG_STR, true) }, backgroundColor = Color.Blue, contentColor = Color.White ) { Icon(Icons.Filled.Add, "") } }, backgroundColor = Color.White, isFloatingActionButtonDocked = false, bottomBar = { BottomNavigationBar(navController = navController) } ) { paddingValues -> Box(modifier = Modifier.padding(paddingValues)) { LazyColumn(modifier = Modifier.fillMaxSize()) { // 仅在加载完成且无数据时显示空提示 if (allItems.itemCount == 0 && allItems.loadState.refresh is LoadState.NotLoading) { item { Text( "这个购物列表里还没有任何物品。", modifier = Modifier.fillMaxWidth().padding(16.dp), textAlign = TextAlign.Center ) } } items(allItems, key = { item -> item.id }) { item -> item?.let { ShoppingListScreenItem( navController = navController, item = it, sharedViewModel = sharedViewModel ) { isChecked -> scope.launch { shoppingListScreenViewModel.changeItemChecked(it, isChecked) } } } } item { Spacer(modifier = Modifier.height(70.dp)) } } // 根据Paging加载状态显示进度条 if (isLoading) { ConditionalCircularProgressBar(isDisplayed = true) } } } }
关键优化点
- 依赖Paging原生状态:用
LazyPagingItems.loadState.refresh判断加载状态,比手动管理loading变量更准确,Paging会自动跟踪加载的开始、成功、失败状态。 - 延迟空提示显示:只有当加载完成且确认无数据时才展示空文本,避免加载过程中出现一闪而过的提示。
- 安全处理空Item:LazyPagingItems在加载过程中可能返回null,通过
item?.let避免空指针异常。 - 修复布局遮挡:应用Scaffold返回的
paddingValues,确保内容不会被TopBar或BottomBar遮挡。
内容的提问来源于stack exchange,提问作者Raj Narayanan
相关产品推荐
相关产品推荐

