19

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!

CaseyB
  • 24,780
  • 14
  • 77
  • 112
Mark Korzhov
  • 2,109
  • 11
  • 31
  • 63
  • 2
    Why would you want to do this? The asynchronous nature of Firebase calls enables your app to account for the timing in response (amongst other things). We can probably assist more if you give us a case example. – Jay Mar 03 '16 at 18:20
  • 1
    @Jay I wanted to get this information only for the sake of interest ;) – Mark Korzhov Mar 09 '16 at 09:05
  • 1
    http://stackoverflow.com/questions/31700830/it-is-possible-to-synchronously-load-data-from-firebase/38663494#38663494 – Alex Jul 29 '16 at 16:27
  • Also read this article for more information: https://medium.com/google-developers/why-are-the-firebase-apis-asynchronous-e037a6654a93 – Doug Stevenson Mar 22 '18 at 16:56
  • 2
    Particular use-case for this requirement is receiving and processing Firebase data in the background where a permanent connection makes less sense. – Richard Le Mesurier Apr 17 '18 at 12:29

5 Answers5

9

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

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
5

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.

touhid udoy
  • 4,005
  • 2
  • 18
  • 31
Patrick Jackson
  • 18,766
  • 22
  • 81
  • 141
1

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);
});
wonsuc
  • 3,498
  • 1
  • 27
  • 30
0

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.

JacksOnF1re
  • 3,336
  • 24
  • 55
  • If you have a setup where you need to query multiple firebase endpoints and return a combined response based on the data you get - then it makes sense to have calls synced. – slott Oct 08 '20 at 10:59
0

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()
philoopher97
  • 772
  • 1
  • 6
  • 18