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
相关产品推荐
相关产品推荐

