'Is it possible to synchronously load data from Firebase?
I'm trying to update parts of a WebView in my Android app with data I'm getting from a peer connected via Firebase. For that, it could be helpful to execute blocking operations that will return the needed data. For example, an implementation of the Chat example that will wait until another chat participant writes something before the push.setValue() to return. Is such a behavior possible with Firebase?
Solution 1:[1]
import com.google.android.gms.tasks.Tasks;
Tasks.await(taskFromFirebase);
Solution 2:[2]
I came up with another way of fetching data synchronously. Prerequisite is to be not on the UI Thread.
final TaskCompletionSource<List<Objects>> tcs = new TaskCompletionSource<>();
firebaseDatabase.getReference().child("objects").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Mapper<DataSnapshot, List<Object>> mapper = new SnapshotToObjects();
tcs.setResult(mapper.map(dataSnapshot));
}
@Override
public void onCancelled(DatabaseError databaseError) {
tcs.setException(databaseError.toException());
}
});
Task<List<Object>> t = tcs.getTask();
try {
Tasks.await(t);
} catch (ExecutionException | InterruptedException e) {
t = Tasks.forException(e);
}
if(t.isSuccessful()) {
List<Object> result = t.getResult();
}
I tested my solution and it is working fine, but please prove me wrong!
Solution 3:[3]
Here's a longer example based on Alex's compact answer:
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;
final FirebaseFirestore firestore = FirebaseFirestore.getInstance();
final CollectionReference chatMessageReference = firestore.collection("chatmessages");
final Query johnMessagesQuery = chatMessageReference.whereEqualTo("name", "john");
final QuerySnapshot querySnapshot = Tasks.await(johnMessagesQuery.get());
final List<DocumentSnapshot> johnMessagesDocs = querySnapshot.getDocuments();
final ChatMessage firstChatMessage = johnMessagesDocs.get(0).toObject(ChatMessage.class);
Note that this is not good practice as it blocks the UI thread, one should use a callback instead in general. But in this particular case this helps.
Solution 4:[4]
If anyone is also thinking about how to use Kotlin's coroutine you can use kotlinx-coroutines-play-services.
Add to your app build.gradle file:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.1.1"
Then simply:
suspend fun signIn(email: String, password: String) {
try {
val auth: FirebaseAuth = FirebaseAuth.getInstance()
auth.signInWithEmailAndPassword(email, password).await()
} catch (e: FirebaseAuthException) {
println("${e.errorCode}: ${e.message}")
}
}
Solution 5:[5]
I made a simple class to call tasks synchronously in Android.
Note that this is similar to Javascript's async await function.
Check my gist.
Here's a sample code to use it.
TasksManager.call(() -> {
Tasks.await(AuthManager.signInAnonymously());
// You can use multiple Tasks.await method here.
// Tasks.await(getUserTask());
// Tasks.await(getProfileTask());
// Tasks.await(moreAwesomeTask());
// ...
startMainActivity();
return null;
}).addOnFailureListener(e -> {
Log.w(TAG, "signInAnonymously:ERROR", e);
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | mrts |
| Solution 2 | |
| Solution 3 | |
| Solution 4 | Rodrigo Queiroz |
| Solution 5 | wonsuc |
