点餐应用中如何通过FoodID从Firebase实时数据库获取食品数据
解决方案
1. 定义组合数据类
首先创建一个数据类,将购物车项与对应的食品数据关联,方便后续状态管理:
data class CartItemWithFood( val cartItem: CartItemData, val food: FoodData? = null // 允许为null,适配加载中/加载失败场景 )
2. 更新状态类 CartState
修改CartState,替换原有购物车列表为组合数据列表,并添加加载状态和错误信息:
data class CartState( val cartItemsWithFood: List<CartItemWithFood> = emptyList(), val isLoading: Boolean = false, val errorMessage: String? = null )
3. 优化Firebase数据获取逻辑(改用Flow)
将回调式的getFood改为返回Flow,更贴合Jetpack Coroutine/Flow的架构习惯,同时完善错误处理:
// FireBaseRepository.kt fun getFood(foodId: String): Flow<FoodData?> = callbackFlow { val listener = object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { // 如果foodId是Firebase节点的key,直接用getValue;否则保持原查询逻辑 val food = snapshot.getValue(FoodData::class.java) // 若用原查询逻辑则替换为:snapshot.children.firstOrNull()?.getValue(FoodData::class.java) trySend(food).isSuccess close() } override fun onCancelled(error: DatabaseError) { trySend(null).isSuccess close(error.toException()) } } // 优化:如果foodId是节点key,直接定位节点而非查询,性能更优 foodsRef.child(foodId).addListenerForSingleValueEvent(listener) awaitClose { foodsRef.child(foodId).removeEventListener(listener) } }
4. 更新ViewModel逻辑
在CartViewModel中,获取购物车数据后并行加载对应食品信息,更新状态:
class CartViewModel : ViewModel() { private val fireBaseRepository = FireBaseRepository.get() private val cartRepository = CartRepository.get() private val _cartState = MutableStateFlow(CartState()) val cartState: StateFlow<CartState> = _cartState.asStateFlow() init { getCart() } private fun getCart() { viewModelScope.launch { _cartState.value = _cartState.value.copy(isLoading = true, errorMessage = null) try { cartRepository.getCart().collect { cartItems -> // 并行批量获取食品数据,提升加载效率 val cartItemsWithFood = cartItems.map { cartItem -> async { val food = fireBaseRepository.getFood(cartItem.foodId).firstOrNull() CartItemWithFood(cartItem, food) } }.awaitAll() _cartState.value = _cartState.value.copy( cartItemsWithFood = cartItemsWithFood, isLoading = false ) } } catch (e: Exception) { _cartState.value = _cartState.value.copy( isLoading = false, errorMessage = "加载失败:${e.message}" ) } } } }
5. 视图层实现(以Jetpack Compose为例)
观察cartState,根据状态展示加载、错误或完整购物车列表:
@Composable fun CartScreen(viewModel: CartViewModel = viewModel()) { val cartState by viewModel.cartState.collectAsStateWithLifecycle() when { cartState.isLoading -> { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { CircularProgressIndicator() } } cartState.errorMessage != null -> { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text(text = cartState.errorMessage!!, color = Color.Red) } } else -> { LazyColumn(modifier = Modifier.fillMaxSize()) { items(cartState.cartItemsWithFood) { item -> if (item.food != null) { CartItemRow( name = item.food.name, price = item.cartItem.price, quantity = item.cartItem.quantity ) } else { // 单个食品加载失败时的占位 CartItemPlaceholder(item.cartItem.quantity) } } } } } } // 示例购物车项行组件 @Composable fun CartItemRow(name: String, price: Double, quantity: Int) { Row( modifier = Modifier .fillMaxWidth() .padding(16.dp), horizontalArrangement = Arrangement.SpaceBetween ) { Column { Text(text = name, fontWeight = FontWeight.Bold) Text(text = "¥${price * quantity}") } Text(text = "x$quantity") } }
内容的提问来源于stack exchange,提问作者HaBuiDuc
相关产品推荐
相关产品推荐

