How to Synchronously Load Data from Firebase

Is it possible to synchronously load data from Firebase?

On a regular JVM, you'd do this with regular Java synchronization primitives.

For example:

// create a java.util.concurrent.Semaphore with 0 initial permits
final Semaphore semaphore = new Semaphore(0);

// attach a value listener to a Firebase reference
ref.addValueEventListener(new ValueEventListener() {
// onDataChange will execute when the current value loaded and whenever it changes
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// TODO: do whatever you need to do with the dataSnapshot

// tell the caller that we're done
semaphore.release();
}

@Override
public void onCancelled(FirebaseError firebaseError) {

}
});

// wait until the onDataChange callback has released the semaphore
semaphore.acquire();

// send our response message
ref.push().setValue("Oh really? Here is what I think of that");

But this won't work on Android. And that's a Good Thing, because it is a bad idea to use this type of blocking approach in anything that affects the user interface. The only reason I had this code lying around is because I needed in a unit test.

In real user-facing code, you should go for an event driven approach. So instead of "wait for the data to come and and then send my message", I would "when the data comes in, send my message":

// attach a value listener to a Firebase reference
ref.addValueEventListener(new ValueEventListener() {
// onDataChange will execute when the current value loaded and whenever it changes
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// TODO: do whatever you need to do with the dataSnapshot

// send our response message
ref.push().setValue("Oh really? Here is what I think of that!");
}

@Override
public void onCancelled(FirebaseError firebaseError) {
throw firebaseError.toException();
}
});

The net result is exactly the same, but this code doesn't required synchronization and doesn't block on Android.

Getting data from firebase in a synchronized way

I want to prevent users from entering the main activity before everything is loaded from firebase completely

In that case, you need to implement a splash page. So you load the data in an asynchronous way and redirect the user to the MainActivity only when the callback is complete.

Implementing a thread that will check if all the data is loaded and will only let main activity to start when the process is over.

There is no need for any other thread. The onDataChange() will fire only when we getting data from the database is complete.

Would the solution I thought of be a good one?

No. The reason is the above.

Should I instead use some other approach like using Firebase Rest Api or anything else?

You should use the Rest API only if needed. But this will not solve the asynchronous manner of this API.

Getting data from firebase in a synchronized way

Definitely NO! You should handle the APIs asynchronously as intended. For more details, you can check my answer from the following post:

  • How to return DataSnapshot value as a result of a method?

Is it possible to send a synchronous request in the Firebase?

There is no way to synchronously load data from the Firebase Database.

While it is common for developers new to Firebase to wish for a synchronous method, it simply doesn't fit with Firebase's data synchronization model. Also see my answer here: Setting Singleton property value in Firebase Listener

Firebase - Get firebase data synchronously in for loop?

There is no way to force Firebase to read the data synchronously.

But if all you want to do is know when all data has been loaded, you can keep a simple counter of the number of items that successfully loaded:

int completedCount = 0;
for(int i=0;i<list.size();i++){
FirebaseDatabase.getInstance().getReference().child(list.get(i)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
Post post = dataSnapshot.getValue(Post.class);
completedCount = completedCount + 1;
if (completedCount == list.size()) {
adapter.notifyDataSetChanged();
}
}

@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
}

How to retrieve data synchronously from Firebase?

Write your own method which takes in a completion handler as its parameter and waits for that block of code to finish. Like so:

 func someMethod(completion: (Bool) -> ()){
rootRef.child("0").child("users")
.queryOrderedByChild("userId")
.queryEqualToValue("578ab1a0e9c2389b23a0e870")
.observeSingleEventOfType(.Value, withBlock: { (snapshot) in

for child in snapshot.children {
self.currQuestion = child.value["currentQuestion"] as! Int
}
print("Current Question is \(self.currQuestion)")
completion(true)
//print(snapshot.value as! Array<AnyObject>)
}, withCancelBlock : { error in
print(error.description)
})
}

And then whenever you want to call that function, call like so:

someMethod{ success in
if success{
//Here currValue is updated. Do what you want.
}
else{
//It is not updated and some error occurred. Do what you want.
}
}

Completion handlers are usually used to wait for a block of code to finish executing completely. P.S. As long as they don't block the main thread, asynchronous requests are made to act synchronous by adding a completion handler like the code shown above.

What it simply does is wait for your currValue to be updated first (receiving the data async from the server) and then when you call someMethod like how I've shown, and since the last and only parameter to the function someMethod is a closure (a.k.a, trailing Closure ), you can skip the parenthesis and call it. Here is a good read about closures. And since the closure is of type (Bool) -> (), you just tell your someMethod when the task is completed which is done like completion(true) in my code, and then while calling it, you call it with success (You can use any word you want) which WILL BE of type Bool as it is declared like so, And then use it in the function call. Hope it helps. :)

Cloud Functions for Firebase: how to read data from Database synchronously?

The code looks fine: you're creating a new promise and returning that from getSomethingFromDbSynchronously(). But the code that calls getSomethingFromDbSynchronously() will then need to wait for the promise to resolve, with something like:

getSomethingFromDbSynchronously("currency").then(function(snapshot) {
console.log(snapshot.val());
});

There is no way to make this synchronous, although you could look into the new async and await keywords, which simply make the above read as if it happens synchronously.

Note, that your code is a bit longer than needed. Since once() already returns a promise, you might as well return that directly:

function getSomethingFromDbSynchronously (currency) {
var db = admin.database();
var ref = db.ref("someref");
return ref.orderByChild("somechild").equalTo("something").once("value");
}

Retrieve data synchronously from firestore database

Consider a scenario.

There is an 'n' no. of collections in your database root and you have their names in a list. You have to get the size() (No. of documents in it) of each of the collections. The only way to get this by synchronous calls is to wait until the pending request has been completed. You can achieve it like this:

 private void syncDocumentCounts() {
if (position > names.size() - 1) {
adapter.notifyDataSetChanged();
} else {
FirebaseFirestore.getInstance().collection(names.get(position)).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
list.add(queryDocumentSnapshots.size());
position++;
syncDocumentCounts();
}
});
}
}

Here,

position = public int = 0

names = list of names of collections

list is the list in which we have to add the value.



Related Topics



Leave a reply



Submit