Android Kotlin Firebase数据转换异常:String转GymLegsModel失败
Firebase数据库类型转换错误:String转GymLegsModel失败
报错日志
2022-12-03 15:56:35.221 16931-16931/com.example.fitnessdiary E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.fitnessdiary, PID: 16931 com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.fitnessdiary.models.GymLegsModel at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:436) at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:232) at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:80) at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203) at com.example.fitnessdiary.activities.startgym.HistoryLegActivity$getUserData$1.onDataChange(HistoryLegActivity.kt:47) at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75) at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63) at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
相关代码
HistoryLegActivity.kt
package com.example.fitnessdiary.activities.startgym import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.example.fitnessdiary.Adapter.GymLegsAdapter import com.example.fitnessdiary.R import com.example.fitnessdiary.models.GymLegsModel import com.google.firebase.database.* import java.time.LocalDate class HistoryLegActivity: AppCompatActivity() { private lateinit var dbref : DatabaseReference private lateinit var userRecyclerview : RecyclerView private lateinit var userArrayList : ArrayList<GymLegsModel> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_gym_leg_history) val uid : String = intent.getStringExtra("UID")?: "No data" val date = LocalDate.now().toString() // recyclerview userRecyclerview = findViewById(R.id.userList) userRecyclerview.layoutManager = LinearLayoutManager(this) userRecyclerview.setHasFixedSize(true) userArrayList = arrayListOf<GymLegsModel>() getUserData(uid, date) } private fun getUserData(uid: String, date: String) { dbref = FirebaseDatabase.getInstance().getReference("Legs") dbref.child(uid).child(date).addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { if (snapshot.exists()){ for (userSnapshot in snapshot.children){ val user = userSnapshot.getValue(GymLegsModel::class.java) userArrayList.add(user!!) } userRecyclerview.adapter = GymLegsAdapter(userArrayList) } } override fun onCancelled(error: DatabaseError) { TODO("Not yet implemented") } }) } }
GymLegsAdapter.kt
package com.example.fitnessdiary.Adapter import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.example.fitnessdiary.R import com.example.fitnessdiary.models.GymLegsModel import kotlin.collections.ArrayList class GymLegsAdapter(private val userList : ArrayList<GymLegsModel>) : RecyclerView.Adapter<GymLegsAdapter.MyViewHolder>() { inner class MyViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ val totalkgL : TextView = itemView.findViewById(R.id.totalkgL) val datestmpL : TextView = itemView.findViewById(R.id.datestmpL) val we1 : TextView = itemView.findViewById(R.id.we1) val we2 : TextView = itemView.findViewById(R.id.we2) val we3 : TextView = itemView.findViewById(R.id.we3) val re1 : TextView = itemView.findViewById(R.id.re1) val re2 : TextView = itemView.findViewById(R.id.re2) val re3 : TextView = itemView.findViewById(R.id.re3) val we21 : TextView = itemView.findViewById(R.id.we21) val we22 : TextView = itemView.findViewById(R.id.we22) val we23 : TextView = itemView.findViewById(R.id.we23) val re21 : TextView = itemView.findViewById(R.id.re21) val re22 : TextView = itemView.findViewById(R.id.re22) val re23 : TextView = itemView.findViewById(R.id.re23) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val itemView = LayoutInflater.from(parent.context).inflate( R.layout.legs_item, parent,false) return MyViewHolder(itemView) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val currentitem = userList[position] holder.totalkgL.text = currentitem.tkg holder.datestmpL.text = currentitem.date holder.we1.text = currentitem.w1 holder.we2.text = currentitem.w2 holder.we3.text = currentitem.w3 holder.re1.text = currentitem.r1 holder.re2.text = currentitem.r2 holder.re3.text = currentitem.r3 holder.we21.text = currentitem.w21 holder.we22.text = currentitem.w22 holder.we23.text = currentitem.w23 holder.re21.text = currentitem.r21 holder.re22.text = currentitem.r22 holder.re23.text = currentitem.r23 } override fun getItemCount(): Int { return userList.size } }
GymLegsModel.kt
package com.example.fitnessdiary.models data class GymLegsModel( var w1 : String ?= null, var r1 : String ?= null, var w2 : String ?= null, var r2 : String ?= null, var w3 : String ?= null, var r3 : String ?= null, var w21 : String ?= null, var r21 : String ?= null, var w22 : String ?= null, var r22 : String ?= null, var w23 : String ?= null, var r23 : String ?= null, var tkg : String ?= null, var date : String ?= null, )
问题原因与解决方法
问题原因
你在getUserData方法中错误遍历了dbref.child(uid).child(date)的子节点,将单个String类型的字段当作完整的GymLegsModel对象转换,导致类型不匹配报错。实际dbref.child(uid).child(date)路径下应该是一个完整的GymLegsModel结构,而非多个String子节点。
解决方法
场景1:仅获取当日数据
如果dbref.child(uid).child(date)对应一个完整的GymLegsModel对象,直接获取快照值即可,无需遍历子节点:
override fun onDataChange(snapshot: DataSnapshot) { if (snapshot.exists()) { val user = snapshot.getValue(GymLegsModel::class.java) user?.let { userArrayList.add(it) userRecyclerview.adapter = GymLegsAdapter(userArrayList) } } }
场景2:获取用户所有日期数据
如果需要展示用户所有历史记录,遍历dbref.child(uid)下的日期节点(每个节点对应一个GymLegsModel):
private fun getUserData(uid: String) { dbref = FirebaseDatabase.getInstance().getReference("Legs").child(uid) dbref.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { if (snapshot.exists()) { userArrayList.clear() for (dateSnapshot in snapshot.children) { val user = dateSnapshot.getValue(GymLegsModel::class.java) user?.let { userArrayList.add(it) } } userRecyclerview.adapter = GymLegsAdapter(userArrayList) } } override fun onCancelled(error: DatabaseError) { // 可添加错误提示,比如Toast.makeText(this, "加载失败", Toast.LENGTH_SHORT).show() } }) }
同时修改onCreate中的调用:getUserData(uid),无需传入date参数。
额外检查项
- 确认Firebase数据库中
Legs/uid/date的结构与GymLegsModel字段完全匹配(字段名大小写一致)。 - 数据库中所有值的类型需为String,与Model定义一致。
- 避免使用
!!强制解包,改用?.let处理空值,防止空指针异常。
内容的提问来源于stack exchange,提问作者Nate
相关产品推荐
相关产品推荐

