使用MVVM架构从Firebase获取数据时返回null问题排查
解决方案
1. 修复Firebase数据获取逻辑
你在FirebaseOrderService中调用db.collection("Order").document().get()时,无参的document()会生成一个新的空文档引用,而不是获取集合中已有的文档。这是核心问题,导致你拿到的是空文档,转换后返回null。
根据你原来的普通代码逻辑(取集合第一个文档),修改后的代码如下:
object FirebaseOrderService { private const val TAG = "FirebaseOrderService" suspend fun getOrderData(): Order? { val db = FirebaseFirestore.getInstance() return try { // 获取Order集合的所有文档,取第一个返回 val querySnapshot = db.collection("Order").get().await() if (querySnapshot.documents.isNotEmpty()) { querySnapshot.documents[0].toOrder() } else { Log.w(TAG, "Order集合中无数据") null } } catch (e: Exception) { Log.e(TAG, "获取订单数据失败", e) FirebaseCrashlytics.getInstance().log("获取订单数据失败") FirebaseCrashlytics.getInstance().setCustomKey("id", "1") FirebaseCrashlytics.getInstance().recordException(e) null } } }
如果你知道目标文档的ID,也可以直接指定文档ID获取:
// 替换成你的目标文档ID db.collection("Order").document("your-document-id").get().await().toOrder()
2. 修正字段拼写与类型解析错误
- 数据库中的字段是
itemQuantity,但你的Order类中写成了itemQuantatiy(多了一个字母a),导致字段无法映射,触发空指针异常。 - 数据库中
itemPrice是Double类型(截图显示19.99),但代码中用getLong获取整数类型,会返回null,加上!!强制非空会直接抛出异常。 - 建议不要用
!!强制非空,改用?:提供默认值,避免转换失败。
修改后的Order.kt:
@Parcelize data class Order( val id: String = "", val picUrl: String = "", val itemName: String = "", val itemPrice: Double = 0.0, val itemAmount: String = "", // 修正字段名拼写 val itemQuantity: Int = 0 ) : Parcelable { companion object { fun DocumentSnapshot.toOrder(): Order? { return try { val id = getString("id") ?: "" val picUrl = getString("picUrl") ?: "" val itemName = getString("itemName") ?: "" // 数据库中itemPrice是Double类型,改用getDouble获取 val itemPrice = getDouble("itemPrice") ?: 0.0 val itemAmount = getString("itemAmount") ?: "" // 修正字段名,用getLong转Int或直接用getInt val itemQuantity = getLong("itemQuantity")?.toInt() ?: 0 Order(id, picUrl, itemName, itemPrice, itemAmount, itemQuantity) } catch (e: Exception) { Log.e(TAG, "转换订单数据失败", e) FirebaseCrashlytics.getInstance().log("转换订单数据失败") FirebaseCrashlytics.getInstance().setCustomKey("id", getString("id") ?: "unknown") FirebaseCrashlytics.getInstance().recordException(e) null } } private const val TAG = "Order" } }
3. 优化ViewModel(可选)
将_orderList命名改为_order更符合语义,同时允许LiveData接收null值:
class SuccessShoppingViewModel: ViewModel() { private val _order = MutableLiveData<Order?>() val order: LiveData<Order?> = _order init { viewModelScope.launch { _order.value = FirebaseOrderService.getOrderData() } } }
内容的提问来源于stack exchange,提问作者Ahmet Yılmaz
相关产品推荐
相关产品推荐

