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

Firebase实时数据库新增子节点时类型转换异常求助

解决Firebase实时数据库新增子节点时的类型转换错误

错误信息

新增子节点时触发应用崩溃,抛出异常:

Process: com.example.myApp, PID: 12458 com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.myApp.model.NoticeModel

数据库结构

当前数据库结构如下:

{  
  "newsNotices": {    
    "dateChanged": {      
      "lastUpdated": "01 January 2024 14:19:18"    
    },    
    "eventItem": {      
      "-NmSeiOMCcp1qeQmj7Mu": {        
        "id": 1703452272,        
        "notice": {          
          "name": "Event Title",          
          "sub_list": [            
            {              
              "link": "https://www.antennahouse.com/hubfs/xsl-fo-sample/pdf/basic-link-1.pdf",              
              "name": "Poster"            
            },            
            {              
              "link": "https://www.antennahouse.com/hubfs/xsl-fo-sample/pdf/basic-link-1.pdf",              
              "name": "Brochure"            
            }          
          ]        
        }      
      },      
      "-NmSelGBrZqTB2kFPHC4": {        
        "id": 1703452284,        
        "notice": {          
          "link": "https://www.antennahouse.com/hubfs/xsl-fo-sample/pdf/basic-link-1.pdf",          
          "name": "Workshop link"        
        }      
      }    
    },    
    "running_time": {      
      "lastRun": 1704191244    
    }  
  }
}

需获取eventItem下的数据,每个子项包含id和notice节点,notice支持两种结构:name+link或name+sub_list。

数据类定义

用于反序列化的数据类:

data class NoticeModel(    
    var id: Long?=null,    
    var notice: newsModel? = null
)

data class newsModel(    
    var link: String? = null,    
    var name: String? = null,    
    var sub_list: List<SubList?>? = null
)

data class SubList(    
    val link: String? = null,    
    val name: String? =null
)

仓库与ViewModel代码

仓库类

class MainRepository {    
    private val database = Firebase.database

    fun fetchNews(noticeLiveData: MutableLiveData<Response<List<NoticeModel>>>, path: String) {
        val newsReference = database.getReference(path)        
        newsReference.addValueEventListener(object : ValueEventListener {            
            override fun onDataChange(snapshot: DataSnapshot) {                
                val newsItemList = mutableListOf<NoticeModel>()                
                for (ds in snapshot.children) {                    
                    val noticeModel = ds.getValue(NoticeModel::class.java)                    
                    if (noticeModel != null) {                        
                        newsItemList.add(noticeModel)                    
                    }                
                }                
                noticeLiveData.postValue(Response.Success(newsItemList))            
            }            

            override fun onCancelled(error: DatabaseError) {                
                noticeLiveData.postValue(Response.Error("Some error occurred")) 
            }        
        })    
    }
}

ViewModel类

class EventsViewModel : ViewModel() {    
    private val repository = MainRepository()    
    private val _latestEventsLiveData = MutableLiveData<Response<List<NoticeModel>>>()    
    val latestEventsLiveData: LiveData<Response<List<NoticeModel>>> = _latestEventsLiveData

    private val path = "/newsNotices/eventItem"

    fun fetchLatestNews() {        
        repository.fetchNews(_latestEventsLiveData, path)    
    }
}

问题原因

错误核心是新增的子节点结构不符合NoticeModel的预期:

  • 可能在eventItem下直接添加了字符串类型的节点,而非包含id和notice的对象
  • 新增的notice节点被错误设置为字符串,而非对象结构
  • 写入数据时路径错误,导致监听的snapshot中混入了非目标结构的数据

解决方案

1. 严格校验新增子节点的结构

确保所有新增到eventItem下的子节点都遵循以下结构:

{
  "id": 1703452284,
  "notice": {
    "name": "示例标题",
    "link": "示例链接"
    // 或
    "name": "带子列表的标题",
    "sub_list": [
      {"name": "子项1", "link": "链接1"},
      {"name": "子项2", "link": "链接2"}
    ]
  }
}

禁止在eventItem下直接写入字符串、数字等非对象类型的数据。

2. 代码中添加异常捕获

修改仓库类的onDataChange方法,增加异常捕获,避免单个错误节点导致整个列表加载崩溃:

override fun onDataChange(snapshot: DataSnapshot) {
    val newsItemList = mutableListOf<NoticeModel>()
    for (ds in snapshot.children) {
        try {
            val noticeModel = ds.getValue(NoticeModel::class.java)
            noticeModel?.let { newsItemList.add(it) }
        } catch (e: DatabaseException) {
            Log.e("FirebaseParseError", "解析节点 ${ds.key} 失败: ${e.message}")
            // 跳过错误节点,不影响其他正常数据的加载
        }
    }
    noticeLiveData.postValue(Response.Success(newsItemList))
}

3. 确保数据类与数据库字段匹配

检查数据类字段名与数据库字段完全一致(大小写敏感),比如newsModel中的sub_list必须和数据库的sub_list字段名完全相同;所有可空字段保留?=null的默认值,保证Firebase能正确反序列化缺失字段的场景。

4. 验证数据写入逻辑

如果通过代码写入数据,确保调用setValue()时传入的是NoticeModel对象,而非字符串:

// 正确写法
val newEventRef = database.getReference("/newsNotices/eventItem").push()
val newNotice = newsModel(name = "新活动", link = "活动链接")
newEventRef.setValue(NoticeModel(id = System.currentTimeMillis(), notice = newNotice))

// 错误写法(会导致子节点变成字符串,触发类型转换错误)
// newEventRef.setValue("错误的字符串内容")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:32:37