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

Firebase新手求助:如何通过addSuccessListener获取嵌套数据?

解决Firebase嵌套数据获取问题

第一步:修正数据类定义

Firebase解析数据需要无参构造函数,因此你的数据类必须为所有属性设置默认值,尤其是列表类型:

import com.google.firebase.Timestamp

data class Punch(
  var roundID: Int = 0,
  var isCorrect: Boolean = true,
  var speed: Double = 0.0
)

data class Training(
  var sessionID: String = "",
  var userId: String = "",
  var username: String = "",
  // 推荐用Firebase Timestamp替代Date,避免序列化兼容问题
  var date: Timestamp = Timestamp.now(),
  // 为列表设置默认空列表,保证无参构造函数可用
  var round_Sessions: MutableList<RoundInfor> = mutableListOf()
)

data class RoundInfor(
  var roundID: String = "",
  var round_length: Double = 0.0,
  var total_punches: Int = 0,
  var correct_punches: Int = 0,
  var incorrect_punches: Int = 0,
  var avg_heart_rate: Double = 0.0,
  var avg_speed: Double = 0.0,
  // 为列表设置默认空列表
  var punches: MutableList<Punch> = mutableListOf()
)

第二步:获取并解析嵌套数据

假设你的训练数据存储在Firebase Realtime Database的trainings节点下,可通过以下两种方式获取嵌套数据:

1. 一次性获取所有训练数据

import com.google.firebase.database.*

val database = FirebaseDatabase.getInstance()
val trainingRef = database.getReference("trainings")

trainingRef.addListenerForSingleValueEvent(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        // 解析所有Training对象,过滤掉解析失败的空值
        val trainingList = snapshot.children.mapNotNull { it.getValue(Training::class.java) }
        
        // 遍历数据,提取嵌套的round_Sessions和punches
        trainingList.forEach { training ->
            println("训练会话ID: ${training.sessionID}")
            training.round_Sessions.forEach { round ->
                println("回合ID: ${round.roundID},总出拳数: ${round.total_punches}")
                round.punches.forEach { punch ->
                    println("出拳速度: ${punch.speed},是否正确: ${punch.isCorrect}")
                }
            }
        }
    }

    override fun onCancelled(error: DatabaseError) {
        println("数据获取失败: ${error.message}")
    }
})

2. 实时监听单个训练数据

如果需要监听特定会话的实时变化,可通过节点路径精准定位:

// 替换为目标会话的实际sessionID
val targetSessionId = "your_target_session_id"
val singleTrainingRef = trainingRef.child(targetSessionId)

singleTrainingRef.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        val training = snapshot.getValue(Training::class.java)
        training?.let {
            // 处理嵌套的回合和出拳数据
            it.round_Sessions.forEach { round ->
                println("当前回合时长: ${round.round_length}")
                round.punches.forEach { punch ->
                    // 对单条出拳数据进行业务处理
                }
            }
        }
    }

    override fun onCancelled(error: DatabaseError) {
        println("数据监听失败: ${error.message}")
    }
})

关键注意事项

  • 属性名严格匹配:数据类的属性名必须与Firebase数据库中的键名完全一致(大小写敏感),比如round_Sessions要和数据库中的键名完全相同。
  • 日期类型兼容:Firebase不直接支持Java原生Date类型,使用Timestamp可避免序列化错误,若需转换为Date,可调用timestamp.toDate()方法。
  • 错误处理不可少:务必实现onCancelled方法,处理权限不足、网络异常等错误场景。

内容的提问来源于stack exchange,提问作者Đinh Đăng Khoa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:40:19