【问题标题】:Firebase: Catch event when data actually reach Firebase Database serverFirebase:当数据实际到达 Firebase 数据库服务器时捕获事件
【发布时间】:2023-03-06 09:30:01
【问题描述】:

我有一个使用 FirebaseDatabase 传输和存储消息的聊天应用。聊天必须在手机在线或离线模式下工作(大多数聊天都是这样),因此消息具有三个状态值:“未发送”、“未读”和“已读”。
1. 消息在本地以“未发送”状态存储。
2. 接下来我的应用实例尝试将其发送到 FirebaseDatabase 并在成功时将状态更改为“未读取”。
3. 最后,当合作伙伴收到消息时,他的应用程序实例在 FirebaseDatabase 上更新消息,状态为“已读”,而我的应用程序实例捕捉到此消息并更新本地消息数据。

当我尝试确定消息是否到达服务器以及何时更改其状态时,主要问题是第二步。

首先,我尝试发送一条消息:

private fun send (firebaseMessage: FirebaseMessage) {
   val ref = FirebaseDatabase.getInstance().getReference("/user-messages/${firebaseMessage.fromUid}/${firebaseMessage.toUid}/${firebaseMessage.Uid}")
   ref.setValue(firebaseMessage)
}

我有 childEventListener 如下:

private fun listen() {
    val ref = FirebaseDatabase.getInstance().getReference("/user-messages/${firebaseMessage.fromUid}/${firebaseMessage.toUid}")
    ref.addChildEventListener(object : ChildEventListener {
        override fun onCancelled(p0: DatabaseError) {}

        override fun onChildMoved(p0: DataSnapshot, p1: String?) {}

        override fun onChildChanged(p0: DataSnapshot, p1: String?) {
            updateMessage(p0.getValue(FirebaseMessage::class.java))
        }

        override fun onChildAdded(p0: DataSnapshot, p1: String?) {
            updateStatusMessage(p0.getValue(FirebaseMessage::class.java))
        }

        override fun onChildRemoved(p0: DataSnapshot) {}

    })
}

主要问题是 childEventListener 触发 onChildAdded 方法,当孩子(新消息)只是添加到 ref 之前,并且独立于它实际到达/与服务器同步,即使电话处于离线状态,因此消息传递到服务器不是完全有保证,所以我不能在 onChildAdded 方法中更改状态。

所以我需要:
1. 将消息状态设置为“未读”并将其发送到 FirebaseDatabase,然后捕获它到达服务器的事件,然后才将该消息的本地存储副本更新为“未读”状态,
2. 或者以某种方式在服务器端设置 FirebaseDatabase 以在到达时更改消息状态,然后此更改将被 onChildChanged 捕获,该更改将更新本地存储的此消息的“未读”状态副本。

【问题讨论】:

    标签: android firebase firebase-realtime-database kotlin


    【解决方案1】:

    setValue 调用返回一个 Task,当消息由服务器处理时完成。

    ref.setValue(firebaseMessage).addOnSuccessListener {
        // Write was successful!
        // ...
    }
    .addOnFailureListener {
        // Write failed
        // ...
    }
    

    另请参阅adding a completion callback 上的文档。

    【讨论】:

    • 但是如果我尝试在 ref.setValue(firebaseMessage).addOnSuccessListener { ... }.addOnFailureListener{ ...} 中以更新状态传递 (firebaseMessage) 它将首先被 ref.onChildEventListener 捕获{ onChildAdd(...) } 并写入本地存储,但实际上可能无法传递到服务器。而且我无法摆脱 onChildEventListener,因为如果我关闭我的应用程序上的一个,它必须捕获其中的所有消息。
    • 本地事件会立即触发,因此您已经可以更新 UI。如果您的用例要求您在数据提交(或拒绝)服务器后执行某些操作,则应使用完成处理程序。如果您需要组合,您可能需要在本地存储其他状态。
    猜你喜欢
    • 2021-11-23
    • 1970-01-01
    • 2019-05-15
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多