Vind Iskald
Vind Iskald

Reputation: 395

Firebase: Catch event when data actually reach Firebase Database server

I have an app with chat that uses FirebaseDatabase to transfer and store messages. The chat must work when phone is online or offline mode (most chats do this way) so the messages have three status values: "not sent", "not read" and "read".
1. When message composed it store locally with "not sent" status.
2. Next my app instance try to send it to FirebaseDatabase and change status to "not read" on success.
3. And finally when partner get the message his app instance updates message on FirebaseDatabase with "read" status and my app instance catch this and updates local message data.

The main problem is with 2nd step when I try to determine wether message arrives on the server and when to change it's status.

First, I try to send a message:

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

And I have childEventListener as follows:

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) {}

    })
}

The main problem is that childEventListener triggers onChildAdded method when the child (new message) simply added to ref, before and independent of it actually arrives/sync with server, even if phone is in offline and so message delivery to server is not guaranteed at all, so I can't change status in onChildAdded method.

And so I need to:
1. Either set message status to "not read" and send it to FirebaseDatabase, then catch event that it arrives on the server and only then update locally stored copy of this message with "not read" status,
2. Or somehow set FirebaseDatabase on the server side to change message status on arrival and then this change will be caught by onChildChanged which will update locally stored copy of this message with "not read" status.

Upvotes: 0

Views: 278

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 599131

The setValue call returns a Task that completes when the message is handled by the server.

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

Also see the documentation on adding a completion callback.

Upvotes: 1

Related Questions