I'm using Firebase Android SDK
and became interested in sending synchronous request instead of asynchronous. According to the documentation, in any request callbacks are presented. But what about the synchronicity?
Thanks!
I'm using Firebase Android SDK
and became interested in sending synchronous request instead of asynchronous. According to the documentation, in any request callbacks are presented. But what about the synchronicity?
Thanks!
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
It is not possible to load data synchronously with the official SDK. However, you can access all the data in firebase using the REST API. This would allow you to make synchronous calls. As mentioned about, Firebase is a realtime database and you will be missing the feature of updates when your data changes.
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.
TasksManager.class
public class TasksManager {
...
public ExecutorService getExecutor() {
if (mDefaultExecutor == null || mDefaultExecutor.isShutdown() || mDefaultExecutor.isTerminated()) {
// Create a new ThreadPoolExecutor with 2 threads for each processor on the
// device and a 60 second keep-alive time.
int numCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
numCores * 2,
numCores * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>()
);
mDefaultExecutor = executor;
}
return mDefaultExecutor;
}
public static <TResult> Task<TResult> call(@NonNull Callable<TResult> callable) {
return Tasks.call(getInstance().getExecutor(), callable);
}
}
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);
});
While it is not possible to load data from the FirebaseDatabase in a synchronous way, it is possible to wait for the load to finish synchronously.
You can wrap your value listener in a CountDownLatch
and count down,
once the onDataChange
or onCancelled
implementation is called.
This is actually what the Tasks
api is doing internally if you call Tasks.await(someTask)
.
You should use the value listener for single event listening, because in this case I assume you don't want continued updates. And use a proper timeout for the CountDownLatch
, since Firebase won't timeout, ever.
reference.addListenerForSingleValueEvent(...);
You also have to take into account, that if you have the FirebaseDatabase cache enabled, the first result might not be the actual value on the server.
I have to add: While this might work, it is against the idea how firebase is designed and supposed to be used, as Frank already said.
If you are using Kotlin, add an extension function:
private suspend fun <TResult> Task<TResult>.await(): TResult? {
return try {
Tasks.await(this)
} catch (e: Exception) {
null
}
}
Now you can do
val snapshot = fireStore.collection(USER_ROOT_PATH).document(documentPath)?.get()?.await()