Firebase - Android - fetchProvidersForEmail - Why are all the calls asynchronous?

后端 未结 1 775
鱼传尺愫
鱼传尺愫 2021-01-15 13:33

I\'m new to Firebase and I\'m having a lot of problems with the fact that all the tasks are called asynchronously.

For example, I am trying to use fetchProvidersForE

相关标签:
1条回答
  • 2021-01-15 14:01

    When you call fetchProvidersForEmail that information is not available in the APK of your app. The Firebase client has to call out to the servers to get this information.

    Given the nature of the internet, this means that it will take an undetermined amount of time before the result comes back from those servers.

    The client has a few options on what to do in the meantime:

    1. wait until the data is available
    2. continue executing and calling you back when the data is available

    Waiting for the data would mean that your code stays simple. But it also means that your app is blocked while the data is being looked up. So: no spinner animation would run, the user can't do anything else (which may be fine for your app, but not for others), etc. This is considered a bad user experience. So bad in fact, that Android will show an Application Not Responding dialog if your app is in this state for 5 seconds.

    So instead, the Firebase SDKs choose the other option: they let your code continue, while they're retrieveing the data from the servers. Then when the data is retrieved, they call back into a code block you provided. Most modern web APIs are built this way, so the sooner you come to grips with it, the sooner you can efficiently use those APIs.

    The easiest way I found to grasps asynchronous programming is by reframing your problems. Right now you're trying to "first determine if the email is already used, then sign the user up or in".

    if (emailIsRegistered(email)) {
        signInUser(email);
    }
    else {
        signUpUser(email);
    }
    

    This approach leads to a emailIsRegistered method that returns a boolean, something that is impossible with asynchronous methods.

    Now let's reframe the problem to "determine if the email is already used. When we know this, sign the user up or in".

    This leads to a different piece of code:

    public static boolean emailIsRegistered(String email) {
    FirebaseAuth auth = FirebaseAuth.getInstance();
    auth.fetchProvidersForEmail(email).addOnCompleteListener(new OnCompleteListener<ProviderQueryResult>() {
         @Override
         public void onComplete(@NonNull Task<ProviderQueryResult> task) {
             if (task.getResult().getProviders().size() > 0) {
                 signUserIn(email);
             }
             signUserUp(email);
         }
    });
    

    We've moved the calls to sign the user up or in into the emailIsRegistered method and invoke then when the result becomes available.

    Now this of course hard-coded the follow up action into the emailIsRegistered method, which makes it harder to re-use. That's why you quite often see a callback being passed into these functions. A great example of that is the OnCompleteListener that you're already using. Once the Firebase client gets the result from the servers, it calls the onComplete method that you passed in.

    Learning to deal with asynchronous calls is both hard and important. I'm not sure if this is my best explanation of the concepts ever. So I'll include some previous explanations (from both me and others):

    • Setting Singleton property value in Firebase Listener
    • Firebase Android: How to read from different references sequentially
    • Is it possible to synchronously load data from Firebase?
    • Knowing when Firebase has completed API call?
    • Gathering data from Firebase asynchronously: when is the data-set complete?
    • What is callback in Android?
    0 讨论(0)
提交回复
热议问题