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

如何在Kotlin/Jetpack Compose中将Firestore文档映射为自定义对象并返回列表

问题:从Firebase Firestore的foods集合获取文档并转换为自定义对象列表

我需要从Firebase中名为foods的集合获取所有文档,将每个文档转换为自定义的Food对象并存入列表,以下是我的尝试代码:

我的Food数据类

data class Food(
    val name: String = "",
    val weight: Double = 0.0,
    val protein: Double = 0.0,
    val carbohydrates: Double = 0.0,
    val fat: Double = 0.0
)

我的Repository代码

override suspend fun getFoodData(): MutableState<List<Food>> {
    val itemList: MutableState<List<Food>> = mutableStateOf(emptyList())

    fb.collection("foods")
        .get()
        .addOnSuccessListener { documents ->
            val items = mutableListOf<Food>()
            for (document in documents) {
                val data = document.data
                val item = Food(
                    data["food_name"] as String,
                    data["food_weight"] as Double,
                    data["food_protein"] as Double,
                    data["food_carbohydrates"] as Double,
                    data["food_fat"] as Double,
                )
                Log.d("DataFoodLog", "valueItem: $item")
                items.add(item)
            }
            itemList.value = items
        }
        .addOnFailureListener {
            Log.e("Firestore", "Error getting documents: ", it)
        }
    Log.d("DataFoodLog","data: ${itemList.value}")
    return itemList
}

我的ViewModel代码

var result = mutableStateOf<List<Food>>(emptyList())
fun getFood() = viewModelScope.launch {
    getFoodDataResponse = Resource.Loading
    result = repo.getFoodData()
}

我的Firebase结构

Firebase结构


解决方案

1. 修复数据类字段映射

Firestore文档字段名(food_name、food_weight等)与Food类属性名不匹配,添加@PropertyName注解关联,方便后续自动映射:

import com.google.firebase.firestore.PropertyName

data class Food(
    @PropertyName("food_name") val name: String = "",
    @PropertyName("food_weight") val weight: Double = 0.0,
    @PropertyName("food_protein") val protein: Double = 0.0,
    @PropertyName("food_carbohydrates") val carbohydrates: Double = 0.0,
    @PropertyName("food_fat") val fat: Double = 0.0
)

2. 优化Repository协程实现

避免回调与协程混用,使用Firebase官方协程扩展await()处理异步请求,同时Repository只负责返回纯数据,不处理UI层状态:

import com.google.firebase.firestore.FirebaseFirestore
import kotlinx.coroutines.tasks.await

override suspend fun getFoodData(): List<Food> {
    return try {
        val documents = fb.collection("foods").get().await()
        documents.mapNotNull { document ->
            document.toObject(Food::class.java)
        }
    } catch (e: Exception) {
        Log.e("Firestore", "Error getting documents: ", e)
        emptyList()
    }
}

3. 修正ViewModel逻辑

ViewModel中更新状态的value而非直接赋值,规范加载状态处理:

var result = mutableStateOf<List<Food>>(emptyList())
var getFoodDataResponse = mutableStateOf<Resource>(Resource.Idle)

fun getFood() = viewModelScope.launch {
    getFoodDataResponse.value = Resource.Loading
    result.value = repo.getFoodData()
    getFoodDataResponse.value = if (result.value.isNotEmpty()) Resource.Success else Resource.Error
}

核心问题说明

  • 原代码用addOnSuccessListener异步回调,函数会直接返回初始空列表,导致ViewModel拿到未更新的数据;用await()可让协程等待请求完成再返回结果。
  • toObject()方法替代手动字段映射,减少出错概率,配合@PropertyName解决字段名不匹配问题。
  • Repository只负责数据获取,不处理UI层MutableState,状态管理交给ViewModel完成。

内容的提问来源于stack exchange,提问作者Mihneas22

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 01:48:26