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

