3

I want to save data in a RealtimeDatabase via databaseReference.child("someChild").setValue(someObject). For my project I need to wait with the further program until the whole writing-process is finished. The Documentation recommends a CompletionListener. But is there a way to wait until this Listener is fired and finished its work?

I tried various approaches like CountDownLatch.await(), synchronized and Thread.join(), but none of those turned out to be the correct solution. The problem is, that things like CountDownLatch.await() block the Listener, and therefore the listener can't be fired. That of course causes the whole process to stuck.

Is there a different and easy approach to this problem?

I basically have written the code

databaseReference.child("someChild).setValue(someObject, 
new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
        System.out.println("This should be 1st.");
    }
});
System.out.println("This should be 2nd.");

The outputs should be in the correct order, but in reality it looks like that:

OUTPUT:

System.out: This should be 2nd.
System.out: This should be 1st.

I hope, that someone in here can help me.

EDIT

My original plan was something like this:

public static void saveThis(SomeObject someObject) {

databaseReference.child("someChild).setValue(someObject, 
new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError databaseError, 
DatabaseReference databaseReference) {
        System.out.println("This should be 1st.");
    }
});
System.out.println("This should be 2nd.");
}

The point is, that I want to call the saveThis(someObject)-method from anywhere. Is there a way to do this?

cpt
  • 77
  • 10
  • 1
    The output is in the expected order. Since Firebase writes data to the database asynchronously, the last log statement is reached before the data is written. Then when the data is written, your `onComplete` is called and logs. Synchronization primitives indeed won't work on Android, see [my answer here for more](https://stackoverflow.com/q/33203379). The normal approach is to move the code that must run when the data has been written into the `onComplete` method. – Frank van Puffelen Oct 01 '17 at 23:03
  • I just edited the question with my original idea. – cpt Oct 02 '17 at 00:00
  • @Frank van Puffelen +1, if you want your other block of code to execute, move your code or a method call inside onComplete. – Andrew Lam Oct 02 '17 at 01:45
  • But wouldn't that get very quickly very messy? Let's say I need five different objects saved as different children (and for whatever reason I decide to use onComplete for every .setValue-call). Then I would have 5 instances of onComplete nested in each other. Isn't there a better, smoother way to do that? – cpt Oct 02 '17 at 01:47

1 Answers1

1

This is happening because of the asynchronous behaviour of onComplete() method which is called even bebore you are trying to print This should be 1st.. This is why you are getting that order in your logcat. There are two approaches to solve this problem.

  1. Everything that you need to achieve must be placed inside the onComplete() method. This means that if you want to use a list for example, both the declaration and the usage must be done inside.

  2. If you want to use some values outside that method, please take a look at my answer from this post. onComplete() has the same behaviour as onDataChange().

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • The first approach is difficult in that specific case, as stated in my comment above. The second approach has in my opinion the same problem: If I want to store more than one time some data, I am ending up with multiple nested listeners(or in that case listener interfaces). So just to be clear: Am I correct that there is no real way to **force** the asynchronous `onComplete()` into a synchronous structure? Because if that is the case, I have to rethink the whole structure and "take the red pill" (thanks @Frank van Puffelen for that great analogy). – cpt Oct 02 '17 at 11:30
  • No, there is not. Unfortunately you cannot force the asynchronous `onComplete()` into a synchronous structure because this is the way in which synchronous methods behave. And yes, there are cases in which you need to rethink the database structure. – Alex Mamo Oct 02 '17 at 11:40