拆分messageId字符串转Long偶发NumberFormatException报错如何解决
问题原因
- 直接原因:未对
snapshot.key的格式做合法性校验,当出现不符合[senderId]_[timestamp]格式的key时(比如key不含下划线、下划线为全角字符、存在多个下划线、前后段格式颠倒),强行拆分取索引1的字段转Long就会抛出异常,你的报错就是因为取到的待转Long字段是纯字母的senderId字符串。 - 隐含原因:使用LiveData的
observe方法监听roomId列表,LiveData是粘性事件,每次触发回调(比如配置变更、roomId列表更新)时,都会给同一个roomId节点重复添加ChildEventListener,同一个消息会被多次回调处理,也会提升异常出现的概率,同时还会造成内存泄漏。
修复方案
1. 避免重复添加监听器
用容器保存已经绑定过监听器的roomId,避免重复绑定,页面销毁时统一移除所有监听器释放资源。
2. 增加格式校验
拆分messageId前先校验格式合法性,转Long时增加异常捕获,非法数据直接跳过处理不要强转强取。
修改后的代码示例
// 类内部添加HashMap保存已绑定的监听器 private val attachedListeners = hashMapOf<String, ChildEventListener>() private fun insertMessage() { viewModel.readRoomIdFriendsDAO().observe(this, { listRoomId -> if (listRoomId != null && listRoomId.isNotEmpty()) { for (item in listRoomId) { // 已经绑定过监听器的roomId直接跳过 if (attachedListeners.containsKey(item)) continue val messageListener = object : ChildEventListener { override fun onChildAdded(snapshot:DataSnapshot,previousChildName: String?) { val messageModel: MessageModel? = snapshot.getValue(MessageModel::class.java) if (messageModel != null) { val rawKey = snapshot.key?.trim() ?: return messageModel.messageId = rawKey messageModel.roomId = item messageModel.uploadSuccess = true // 拆分后先校验长度 val listTemp = rawKey.split("_") if (listTemp.size >= 2) { messageModel.messageSenderId = listTemp[0] // 安全转Long,失败则跳过 runCatching { listTemp[1].trim().toLong() }.onSuccess { timestamp -> messageModel.messageTimestamp = timestamp Log.e(TAG,"senderId: ${messageModel.messageSenderId}") Log.e(TAG,"timestamp: $timestamp") messageViewModel.insertMessageDAO(messageModel) }.onFailure { Log.e(TAG, "时间戳格式非法,messageId:$rawKey", it) } } else { Log.e(TAG, "messageId格式不合法,缺少下划线:$rawKey") } } } override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {} override fun onChildRemoved(snapshot: DataSnapshot) {} override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {} override fun onCancelled(error: DatabaseError) {} } messageRef.child(item).addChildEventListener(messageListener) attachedListeners[item] = messageListener } } }) } // 页面销毁时移除所有监听器 override fun onDestroy() { super.onDestroy() attachedListeners.forEach { (roomId, listener) -> messageRef.child(roomId).removeEventListener(listener) } attachedListeners.clear() }
内容的提问来源于stack exchange,提问作者Lộc Trần Phước
相关产品推荐
相关产品推荐

