如何在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结构

解决方案
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
相关产品推荐
相关产品推荐

