Kotlin从Firebase实时数据库获取嵌套节点数据时遇到类型转换错误及数据为空问题求助
Hi there! Let's break down what's going wrong with your Firebase data fetching code and fix it step by step.
第一个错误:类型转换异常(String转AttendanceModel)
你的第一个代码片段里,你直接定位到了danielle下的2023-04-08节点,这个节点的子节点是address、check_in、check_out——这些都是字符串类型的字段,而不是AttendanceModel对象。当你用for (h in snapshot.children)遍历这些子节点时,每个h对应的是单个字符串值(比如"Thomas street"),这时候调用h.getValue(AttendanceModel::class.java)自然会报错,因为没法把String转换成你的自定义数据类。
正确的思路是:直接把整个2023-04-08节点转换成AttendanceModel对象,而不是遍历它的子节点。
第二个错误:数据为空的原因
第二个代码片段里,你遍历danielle的子节点(也就是各个日期节点,比如2023-04-08、2023-04-10),然后对每个h调用h.child("2023-04-08")——这相当于在日期节点(比如2023-04-08)下去找名为2023-04-08的子节点,显然这个节点不存在,所以date的value是null,后续自然拿不到数据。
正确的实现方式
根据你的需求,分两种场景给出代码:
场景1:获取指定用户指定日期的考勤数据
如果你只想拿danielle在2023-04-08的考勤数据,直接把整个日期节点转换成AttendanceModel即可:
val attModel = arrayListOf<AttendanceModel>() Firebase.database.getReference("Attendance").child("danielle").child("2023-04-08") .addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { // 直接将整个节点转换为AttendanceModel val data = snapshot.getValue(AttendanceModel::class.java) data?.let { attModel.add(it) } } override fun onCancelled(error: DatabaseError) { // 别忘了处理取消事件,方便排查问题 Log.e("FirebaseError", error.message) } })
场景2:获取指定用户所有日期的考勤数据
如果想拿到danielle所有日期的考勤记录,遍历她的子节点(各个日期节点),每个节点直接转成AttendanceModel:
val todays = arrayListOf<AttendanceModel>() Firebase.database.getReference("Attendance").child("danielle") .addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { todays.clear() // 避免重复添加数据 for (dateSnapshot in snapshot.children) { // 每个dateSnapshot就是一个日期节点,直接转成AttendanceModel val dataUser = dateSnapshot.getValue(AttendanceModel::class.java) dataUser?.let { todays.add(it) } } // 这里可以更新UI或者处理数据 } override fun onCancelled(error: DatabaseError) { Log.e("FirebaseError", error.message) } })
关于数据类的小提醒
你的AttendanceModel里有个loc_name字段,但在你的数据库结构里并没有这个字段。Firebase在转换的时候会自动忽略不存在的字段,所以这没问题,但如果不需要的话可以考虑去掉,避免混淆。另外,要确保数据类的字段名和数据库里的key完全一致(比如你的数据库是address,数据类也是address,这点你已经做对了)。
备注:内容来源于stack exchange,提问作者Adela Nadhifa

