You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

点餐应用中如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 07:44:51