Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to listen for Firebase setValue completion

I would like to set up something like a groupchat in Firebase. If you have the correct group ID, you can join.

The problem is that Firebase references always exist. They are created dynamically. To allow some error checking in the joining process, I want to add the user who created the new database entry to a table of users.

public void createParty() {

    // you need to be signed in to create a party
    assertState(DBState.SignedIn);

    // create a new party
    ourPartyDatabaseReference = partiesDatabaseReference.push();
    usersDatabaseReference = ourPartyDatabaseReference.child("users");

    // write our user to the table of users, now the ourPartyReference actually exists
    // and if you look for existing users, you will always find at least the original creator
    Task initTask = usersDatabaseReference.child(user.getUid()).setValue(true);

After this has been done, I call a helper method connectToParty to set up a few references and change the state of the database connection to DBState.Connected. Now you can take the key of the party and transmit it to other users. With key I mean the name in firebase.

The problem is: Other users need to check whether they used a valid key to connect. They do this by checking if there is data under key/users. So the party is only valid if the first user has been successfully written to the database.

Sometimes the write process takes very long, sometimes it seems to fail completely. So I've set up listeners:

Task initTask = usersDatabaseReference.child(user.getUid()).setValue(true);

initTask.addOnSuccessListener(new OnSuccessListener() {
    @Override
    public void onSuccess(Object o) {
        connectToParty();
    }
});

initTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        changeState(DBState.SignedIn, DBTransition.Failure);
    }
});

This is covered by a test. The test sets up a connection, signs in and creates a party. If the party is created within a specific timeout, the test passes.

9 out of 10 times this works without a problem. But sometimes the test fails.

This has nothing to do with the timeout being to short. The callbacks from the task are simply not called. I read that this callback only works if your connection is online.

So I added firebaseDatabase.goOnline(); to my code, just before the task. But that doesn't help.

I'm connected to the internet over LAN. All the other tests pass, and they need to access firebase, too. For example for the sign-in process.

What is the correct way to write a value to the database and wait for the write to complete ?

like image 631
lhk Avatar asked Dec 04 '22 21:12

lhk


2 Answers

For the Kotlin users, you can use this

firebaeRef.setValue("your_value", { error, ref ->
            //setValue operation is done, you'll get null in errror and ref is the path reference for firebase database
        })

Here, firebaeRef is the reference to the node/child who's value is set and your_value is the value to be set.

like image 107
Kishan Solanki Avatar answered Dec 26 '22 04:12

Kishan Solanki


As the offical documentation says:

If you'd like to know when your data has been committed, you can add a completion listener. Both setValue() and updateChildren() take an optional completion listener that is called when the write has been committed to the database.

This is a simple example:

ref.setValue("I'm writing data to a Firebase database", new Firebase.CompletionListener() {
    @Override
    public void onComplete(FirebaseError firebaseError, Firebase firebase) {
        if (firebaseError != null) {
            System.out.println("Data could not be saved. " + firebaseError.getMessage());
        } else {
            System.out.println("Data saved successfully.");
        }
    }
});
like image 38
Alex Mamo Avatar answered Dec 26 '22 05:12

Alex Mamo