Firebase - Android - fetchProvidersForEmail - 为什么所有的调用都是异步的? [英] Firebase - Android - fetchProvidersForEmail - Why are all the calls asynchronous?

查看:413
本文介绍了Firebase - Android - fetchProvidersForEmail - 为什么所有的调用都是异步的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Firebase的新手,我遇到了很多问题,所有任务都是异步调用的。



例如,我正在尝试使用fetchProvidersForEmail知道是否应该引导用户注册或登录。但是,到任务完成时,已经太晚了。

我不确定如果它是明确的,但这里是我目前的代码(哪些工作)和下面是我想要创建的方法。

  public static void printProviders(String email){
FirebaseAuth auth = FirebaseAuth.getInstance ();
auth.fetchProvidersForEmail(email).addOnCompleteListener(new OnCompleteListener< ProviderQueryResult>(){
@Override $ b $ public void onComplete(@NonNull Task< ProviderQueryResult> task){
Log。 (TAG,We have+ task.getResult()。getProviders()。size()+results。);
for(int i = 0; i< task.getResult()。getProviders ().size(); i ++){
Log.d(TAG,Provider+(i + 1)+:+ task.getResult()。getProviders()。get(i));
}
}
}
);



$ b $ p
$ b这是我想要创建的方法的伪代码当然,这是行不通的)...
$ b $ pre $ public static boolean emailIsRegistered(String email){
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.fetchProvidersForEmail(email).addOnCompleteListener(new OnCompleteListener< ProviderQueryResult>(){
@Override $ b $ public void onComplete(@NonNull Task< ProviderQueryResult> task){
if ().getResult()。size()> 0){
return true;
}
return false;
}
});





$ b

然而,这是行不通的,因为return语句对于onComplete()因为这个任务是异步执行的...



我是新手。我试图通过StackOverflow搜索,但找不到任何帮助我。希望有人可以帮忙。



谢谢!

解决方案

请致电 fetchProvidersForEmail 该信息在您的应用的APK中不可用。 Firebase客户端必须致电服务器以获取此信息。



考虑到互联网的性质,这意味着在结果从这些服务器返回之前需要一定的时间。



客户端有几个选项可供选择:


  1. 等待数据可用



  2. $ b 等待数据意味着数据可用你的代码保持简单。但这也意味着在查找数据时,您的应用程序被阻止。所以:没有微调动画会运行,用户不能做任何事情(这可能适用于您的应用程序,但不适用于其他),等等。这被认为是不好的用户体验。事实上,如果你的应用程序是 Android将显示一个应用程序不响应对话框在这种状态下5秒钟

    因此,Firebase SDK会选择其他选项:让代码在检索数据时继续执行从服务器。然后,当数据被检索到时,他们回到你提供的代码块。大多数现代Web API都是以这种方式构建的,所以越早熟悉它,越早可以高效地使用这些API。

    最简单的方法就是抓住异步编程是通过重组你的问题。现在,您正试图首先确定电子邮件是否已被使用,然后在用户上或登录。

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

    $ / code>

    这个方法导致 emailIsRegistered 返回的方法是一个布尔值,这是异步方法不可能实现的。



    现在让我们将问题重新设计为确定电子邮件是否已被使用,当我们知道这一点时,请将用户登录或注册。



    这导致了一段不同的代码:

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

    我们将呼叫转移到 emailIsRegistered 方法,当结果变为可用时调用



    课程将后续操作硬编码到 emailIsRegistered 方法中,这使得难以重复使用。这就是为什么你经常看到传入这些函数的回调函数。一个很好的例子就是你已经使用的 OnCompleteListener 。一旦Firebase客户端从服务器获得结果,它就会调用您传入的 onComplete 方法。



    学习处理异步通话既困难又重要。我不确定这是否是我对有史以来概念的最好解释。所以我会包括一些以前的解释(从我和其他人):


    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 fetchProvidersForEmail to know if I should direct the user to sign up or log in. However, by the time the task finishes, it's too late.

    I am not sure if it's clear but here is my current code (which works) and below is the method I would want to create. How can I get that done?

    public static void printProviders(String email) {
        FirebaseAuth auth = FirebaseAuth.getInstance();
        auth.fetchProvidersForEmail(email).addOnCompleteListener(new OnCompleteListener<ProviderQueryResult>() {
                @Override
                public void onComplete(@NonNull Task<ProviderQueryResult> task) {
                    Log.d(TAG, "We have " + task.getResult().getProviders().size() + " results.");
                    for (int i = 0; i < task.getResult().getProviders().size(); i++) {
                        Log.d(TAG, "Provider " + (i+1) + ": " + task.getResult().getProviders().get(i));
                    }
                }
            }
        );
    }
    

    Here is the pseudo-code of the method I would want to create (of course, this doesn't work)...

        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) {
                     return true;
                 }
                 return false;
             }
        });
    }
    

    However, this does not work because the return statement is void for onComplete() and because the task is executed asynchronously...

    I am new to this. I tried to search through StackOverflow but couldn't find anything that helped me. Hopefully someone can help.

    Thank you!

    解决方案

    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):

    这篇关于Firebase - Android - fetchProvidersForEmail - 为什么所有的调用都是异步的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆