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

如何在Kotlin中为Firebase实时数据库按用户ID构建会话列表

问题:基于Kotlin和Firebase Realtime Database实现会话数据结构

需求与目标数据结构

我正在开发一个基于Kotlin和Firebase Realtime Database的Android项目,需要构建如下数据结构:每个用户节点下包含与其他用户的会话列表,每个会话存储双方交互的最新消息。

目标数据结构示例:

{
  "403": {
    "conversations": [
      {
        "id": "conversation_403_407_2024-05-08_18:31:38",
        "latest_message": {
          "date": "2024-05-08 18:32:43",
          "isRead": false,
          "message": "Jhbhjbhbckskjcbdsljkcnjldsvljdsjlcdskjcvbjkdsbvkjdvjlwvjl"
        },
        "name": "djFbtu315",
        "otherUserId": 407
      }
    ]
  },
  "407": {
    "conversations": [
      {
        "id": "conversation_403_407_2024-05-08_18:31:38",
        "latest_message": {
          "date": "2024-05-08 18:32:43",
          "isRead": true,
          "message": "Jhbhjbhbckskjcbdsljkcnjldsvljdsjlcdskjcvbjkdsbvkjdvjlwvjl"
        },
        "name": "my basic profile",
        "otherUserId": 403
      },
      {
        "id": "conversation_408_407_2024-05-08_19:31:02",
        "latest_message": {
          "date": "2024-05-08 19:31:02",
          "isRead": true,
          "message": "22"
        },
        "name": "Muhammad",
        "otherUserId": 408
      },
      {
        "id": "conversation_507_407_2024-05-08_19:38:47",
        "latest_message": {
          "date": "2024-05-08 19:39:15",
          "isRead": true,
          "message": "22"
        },
        "name": "Manuel Crandall",
        "otherUserId": 507
      }
    ]
  }
}

当前问题

无法正确将会话添加到用户节点内的会话列表,也不知道如何在会话已存在时更新最新消息。

现有代码

fun addUser(userId: String) {
    val usersReference: DatabaseReference = FirebaseDatabase.getInstance().getReference("Users")
    val userDetails = intent.getParcelableExtra<ConnectionDetailDTO>("USER_DETAILS")
    otherUserId = userDetails?.id!!
    currentUserId = currentUser?.id!!

    usersReference.child(userId).get().addOnSuccessListener { snapshot ->
        if (snapshot.exists()) {
            Log.d(TAG, "User already exists with ID: $userId")
        } else {
            val user = hashMapOf(
                "conversations" to listOf<Conversations>()
            )
            usersReference.child(userId).setValue(true)
                .addOnSuccessListener {
                    Log.d(TAG, "User created with ID: $userId")
                }
                .addOnFailureListener { e ->
                    Log.d(TAG, "Error creating user: $e")
                }
        }
    }.addOnFailureListener { e ->
        Log.d(TAG, "Error checking user existence: $e")
    }
}

使用的数据类

data class Conversations(
    val id: String = "",
    val latest_message: LatestMessage = LatestMessage(),
    val name: String = "",
    val otherUserId: Int = 0 
) {
    data class LatestMessage(
        val date: String = "",
        val isRead: Boolean = false,
        val message: String = "" 
    )
}
data class ChatUser(
    val id: Long = 0, // User ID
    val conversations: List<Conversations> = emptyList()
)

解决方案

1. 修复用户创建逻辑

原代码中usersReference.child(userId).setValue(true)不符合目标结构,应该创建包含空会话列表的ChatUser对象存入数据库:

fun addUser(userId: String) {
    val usersReference = FirebaseDatabase.getInstance().getReference("Users")
    
    usersReference.child(userId).get().addOnSuccessListener { snapshot ->
        if (snapshot.exists()) {
            Log.d(TAG, "User already exists with ID: $userId")
        } else {
            // 创建符合结构的用户对象
            val chatUser = ChatUser(id = userId.toLong(), conversations = emptyList())
            usersReference.child(userId).setValue(chatUser)
                .addOnSuccessListener {
                    Log.d(TAG, "User created with ID: $userId")
                }
                .addOnFailureListener { e ->
                    Log.d(TAG, "Error creating user: $e")
                }
        }
    }.addOnFailureListener { e ->
        Log.d(TAG, "Error checking user existence: $e")
    }
}

2. 实现会话的添加/更新逻辑

编写方法同时处理会话新增与更新,并且同步更新双方用户的会话记录:

fun updateOrAddConversation(currentUserId: String, otherUserId: String, otherUserName: String, currentUserName: String, messageContent: String) {
    val db = FirebaseDatabase.getInstance()
    val usersRef = db.getReference("Users")
    
    // 生成唯一会话ID:按用户ID排序,确保双方会话ID一致
    val sortedIds = listOf(currentUserId, otherUserId).sorted()
    val timestamp = SimpleDateFormat("yyyy-MM-dd_HH:mm:ss", Locale.getDefault()).format(Date())
    val conversationId = "conversation_${sortedIds[0]}_${sortedIds[1]}_$timestamp"
    
    // 更新当前用户的会话
    usersRef.child(currentUserId).child("conversations").get().addOnSuccessListener { snapshot ->
        val existingConversations = snapshot.getValue(object : GenericTypeIndicator<List<Conversations>>() {})?.toMutableList() ?: mutableListOf()
        val targetIndex = existingConversations.indexOfFirst { it.otherUserId == otherUserId.toInt() }
        
        val newLatestMsg = Conversations.LatestMessage(
            date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date()),
            isRead = false,
            message = messageContent
        )
        
        if (targetIndex != -1) {
            // 会话已存在,更新最新消息
            existingConversations[targetIndex] = existingConversations[targetIndex].copy(latest_message = newLatestMsg)
        } else {
            // 会话不存在,添加新会话
            val newConversation = Conversations(
                id = conversationId,
                latest_message = newLatestMsg,
                name = otherUserName,
                otherUserId = otherUserId.toInt()
            )
            existingConversations.add(newConversation)
        }
        
        usersRef.child(currentUserId).child("conversations").setValue(existingConversations)
    }
    
    // 更新对方用户的会话
    usersRef.child(otherUserId).child("conversations").get().addOnSuccessListener { snapshot ->
        val existingConversations = snapshot.getValue(object : GenericTypeIndicator<List<Conversations>>() {})?.toMutableList() ?: mutableListOf()
        val targetIndex = existingConversations.indexOfFirst { it.otherUserId == currentUserId.toInt() }
        
        val newLatestMsg = Conversations.LatestMessage(
            date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date()),
            isRead = false,
            message = messageContent
        )
        
        if (targetIndex != -1) {
            existingConversations[targetIndex] = existingConversations[targetIndex].copy(latest_message = newLatestMsg)
        } else {
            val newConversation = Conversations(
                id = conversationId,
                latest_message = newLatestMsg,
                name = currentUserName,
                otherUserId = currentUserId.toInt()
            )
            existingConversations.add(newConversation)
        }
        
        usersRef.child(otherUserId).child("conversations").setValue(existingConversations)
    }
}

关键说明

  • 会话ID生成:对用户ID排序后拼接,保证同一会话在双方用户节点下ID一致,避免重复创建。
  • 双向同步:发送消息时必须同时更新双方的会话记录,确保数据一致性。
  • 数据解析:使用GenericTypeIndicator正确解析Firebase返回的List<Conversations>类型数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:32:03