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

Kotlin读取Firebase数据报错java.lang.String无法转HashMap如何解决

问题根因

  • 崩溃发生在var map = it.value as HashMap<String,String>这行代码:你直接将DataSnapshot返回的内容强转为HashMap,但实际该节点下存储的是String类型,触发类型转换异常。
  • 额外存在逻辑问题:Firebase的ValueEventListener是异步回调,你写的retrieve方法会直接返回空列表,就算后续数据加载完成,RecyclerView也不会自动刷新。

修复方案

1. 先确认数据库结构

你的Scholars节点需要符合如下结构才能直接映射为User对象:

{
  "Scholars": {
    "节点ID1": {
      "scholarName": "姓名1",
      "scholarStatus": "状态1"
    },
    "节点ID2": {
      "scholarName": "姓名2",
      "scholarStatus": "状态2"
    }
  }
}

2. 调整User实体类,适配Firebase序列化

Firebase反射序列化需要空构造方法,修改后代码:

class User {
    var scholarName: String = ""
    var scholarStatus: String = ""

    // 增加无参构造方法
    constructor() : this("", "")

    constructor(scholarName: String, scholarStatus: String) {
        this.scholarName = scholarName
        this.scholarStatus = scholarStatus
    }
}

3. 重写ProfileActivity的数据加载逻辑

去掉有问题的retrieve方法,改用全局列表存储数据,加载完成后主动通知适配器刷新:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityProfileBinding.inflate(layoutInflater)
    setContentView(binding.root)

    //configure action
    actionBar = supportActionBar!!
    actionBar.title = "Profile"

    //init firebase auth
    firebaseAuth = FirebaseAuth.getInstance()
    checkUser()

    //handle click, logout
    binding.logoutBtn.setOnClickListener {
        firebaseAuth.signOut()
        checkUser()
    }

    //Initialize controls
    scholarName = findViewById(R.id.txtScholarName)
    scholarStatus = findViewById(R.id.txtQuotaStatus)

    users = ArrayList<User>()
    // 初始化适配器绑定全局空列表
    adapter = UserAdapter(this, users)
    rvData = findViewById(R.id.rvData)
    var ll: LinearLayoutManager = LinearLayoutManager(applicationContext)
    rvData.layoutManager = ll
    rvData.adapter = adapter
    // 调用异步加载数据方法
    loadScholarData()
}

private fun loadScholarData(){
    val ref = FirebaseDatabase.getInstance("***********").getReference("Scholars")
    ref.addValueEventListener(object:ValueEventListener{
        override fun onDataChange(snapshot: DataSnapshot) {
            users.clear()
            snapshot.children.forEach{ dataSnap ->
                // 用Firebase自带的序列化能力,避免手动强转HashMap的类型异常
                val user = dataSnap.getValue(User::class.java)
                user?.let {
                    users.add(it)
                }
            }
            // 数据加载完成后通知列表刷新
            adapter.notifyDataSetChanged()
        }

        override fun onCancelled(error: DatabaseError) {
            Toast.makeText(this@ProfileActivity, "数据加载失败:${error.message}", Toast.LENGTH_SHORT).show()
        }
    })
}

4. 特殊场景兼容

如果你的Scholars节点下的子节点确实存储的是字符串而非对象,就去掉强转HashMap的逻辑,直接通过it.value.toString()取值,再按照你的业务逻辑组装User对象即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 04:54:02