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

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参数。

额外检查项

  1. 确认Firebase数据库中Legs/uid/date的结构与GymLegsModel字段完全匹配(字段名大小写一致)。
  2. 数据库中所有值的类型需为String,与Model定义一致。
  3. 避免使用!!强制解包,改用?.let处理空值,防止空指针异常。

内容的提问来源于stack exchange,提问作者Nate

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:35:25