Firebase数据库类型转换异常:String转Kelas类致Kotlin应用崩溃
问题描述
运行Kotlin开发的Edumathh应用时崩溃,抛出com.google.firebase.database.DatabaseException异常,提示无法将java.lang.String类型转换为com.edushare.edumathh.home.kelas.model.Kelas类型。
相关代码
Fragment代码
class KelasFragment : Fragment() { private lateinit var preferences: Preferences private lateinit var mDatabase: DatabaseReference private var datalist = ArrayList<Kelas>() private var _binding : FragmentKelasBinding? = null private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = FragmentKelasBinding.inflate(inflater, container, false ) return binding.root } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) preferences = Preferences(requireActivity().applicationContext) mDatabase = FirebaseDatabase.getInstance().getReference("Kelas") binding.tvName.text = preferences.getValues("nama") binding.tvSchool.text = preferences.getValues("sekolah") Glide.with(this) .load(preferences.getValues("url")) .apply(RequestOptions.circleCropTransform()) .into(binding.ivAvatar) binding.rvKelas.layoutManager = LinearLayoutManager(context) getData() } private fun getData() { mDatabase.addValueEventListener(object : ValueEventListener{ override fun onDataChange(snapshot: DataSnapshot) { datalist.clear() for (getSnapshot in snapshot.children){ var kelas = getSnapshot.getValue(Kelas::class.java) datalist.add(kelas!!) } binding.rvKelas.adapter = KelasTersediaAdapter(datalist){ var intent = Intent(context,DetailKelasActivity::class.java).putExtra("data",it) startActivity(intent) } } override fun onCancelled(error: DatabaseError) { Toast.makeText(context, ""+ error.message, Toast.LENGTH_LONG).show() } }) } override fun onDestroyView() { super.onDestroyView() _binding = null } }
Firebase数据库结构
{ "Istilah": { "Median": { "desc": "Nilai tengah", "istilah": "Median" }, "Rata-rata": { "desc": "Rata-rata", "istilah": "Mean" } }, "Kelas": { "desc": "Kelas XII semester II", "title": "Statistika" }, "User": { "1": { "email": "bagicode@gmail.com", "nama": "Robby Dianputra", "password": "1", "saldo": "500000", "url": "https://yt3.ggpht.com/a/AGF-l79H3wIgvBVl0bD5No1VMvfjo_DuhdPjQXWfvw=s288-c-k-c0xffffffff-no-rj-mo", "username": "1" }, "009": { "nama": "\"Rahmatul Ulya\"", "password": "009", "sekolah": "SMAN 1 Banda Aceh", "url": "https://firebasestorage.googleapis.com/v0/b/edumath-f7c8a.appspot.com/o/images%2F178a0569-f4f0-49e4-9f98-f4fb58a94f6d?alt=media&token=58cb5004-607f-4f0c-afa4-8b821f024b33", "username": "009" } } }
LogCat日志
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.edushare.edumathh, PID: 21519 com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.edushare.edumathh.home.kelas.model.Kelas 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.edushare.edumathh.home.kelas.KelasFragment$getData$1.onDataChange(KelasFragment.kt:59) 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:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5254) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) I/Process: Sending signal. PID: 21519 SIG: 9
解决方案
问题根源在于数据库结构和代码逻辑不匹配:Kelas节点直接存储了单个Kelas对象的属性(desc和title),但代码里却遍历snapshot.children,把每个子节点(也就是desc和title这两个字符串值)尝试转换成Kelas对象,自然会触发类型转换失败。
提供两种修复方式:
方式一:调整数据库结构(推荐,支持多班级数据)
修改Kelas节点为包含多个子节点的列表结构,每个子节点是独立的Kelas对象,示例如下:
"Kelas": { "kelas1": { "desc": "Kelas XII semester II", "title": "Statistika" }, "kelas2": { "desc": "Kelas XI semester I", "title": "Aljabar" } }
调整后代码中的遍历逻辑可正常工作,每个getSnapshot对应一个完整的Kelas对象。
方式二:调整代码逻辑(适配当前单班级数据库结构)
如果暂时只需要单个班级数据,直接读取Kelas节点的数据,无需遍历子节点,修改后的getData函数如下:
private fun getData() { mDatabase.addValueEventListener(object : ValueEventListener{ override fun onDataChange(snapshot: DataSnapshot) { datalist.clear() // 直接读取当前节点的Kelas对象 val kelas = snapshot.getValue(Kelas::class.java) kelas?.let { datalist.add(it) } binding.rvKelas.adapter = KelasTersediaAdapter(datalist){ val intent = Intent(context,DetailKelasActivity::class.java).putExtra("data",it) startActivity(intent) } } override fun onCancelled(error: DatabaseError) { Toast.makeText(context, error.message, Toast.LENGTH_LONG).show() } }) }
额外注意:需确保Kelas数据类的属性名称与数据库键完全一致(desc、title),且包含空参构造函数,示例如下:
data class Kelas( val desc: String? = null, val title: String? = null )
内容的提问来源于stack exchange,提问作者Rahmatul Ulya
相关产品推荐
相关产品推荐

