android - Firebase - Android - fetchProvidersForEmail - 为什么所有调用都是异步的?

标签 android firebase firebase-authentication

我是 Firebase 新手,由于所有任务都是异步调用,因此遇到很多问题。

例如,我尝试使用 fetchProvidersForEmail 来了解是否应该引导用户注册或登录。但是,当任务完成时,为时已晚。

我不确定是否清楚,但这是我当前的代码(可以工作),下面是我想要创建的方法。我怎样才能做到这一点?

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));
                }
            }
        }
    );
}

这是我想要创建的方法的伪代码(当然,这不起作用)...

    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;
         }
    });
}

但是,这不起作用,因为 onComplete() 的 return 语句无效,并且任务是异步执行的...

我对此很陌生。我尝试在 StackOverflow 中搜索,但找不到任何对我有帮助的内容。希望有人能帮忙。

谢谢!

最佳答案

当您调用 fetchProvidersForEmail 时,该信息在您应用的 APK 中不可用。 Firebase 客户端必须调用服务器才能获取此信息。

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

客户有几个选项可以选择同时做什么:

  1. 等待数据可用
  2. 继续执行并在数据可用时给您回电

等待数据意味着您的代码保持简单。但这也意味着您的应用程序在查找数据时被阻止。因此:不会运行旋转动画,用户无法执行任何其他操作(这可能对您的应用程序来说很好,但对其他人来说则不然)等。这被认为是糟糕的用户体验。事实上很糟糕,Android will show an Application Not Responding dialog if your app is in this state for 5 seconds .

因此,Firebase SDK 选择了另一个选项:它们让您的代码继续运行,同时从服务器检索数据。然后,当检索数据时,它们会回调到您提供的代码块。大多数现代 Web API 都是以这种方式构建的,因此您越早掌握它,就能越早有效地使用这些 API。

我发现掌握异步编程的最简单方法是重新构建问题。现在您正在尝试“首先确定电子邮件是否已被使用,然后让用户注册或登录”。

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

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

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

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

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);
     }
});

我们已将用户注册或注册的调用移至 emailIsRegistered 方法中,并在结果可用时调用。

现在,这当然将后续操作硬编码到 emailIsRegistered 方法中,这使得重用变得更加困难。这就是为什么您经常看到回调被传递到这些函数中的原因。一个很好的例子就是您已经在使用的 OnCompleteListener。 Firebase 客户端从服务器获取结果后,就会调用您传入的 onComplete 方法。

学习处理异步调用既困难又重要。我不确定这是否是我对这些概念的最好解释。因此,我将添加一些之前的解释(来 self 和其他人):

关于android - Firebase - Android - fetchProvidersForEmail - 为什么所有调用都是异步的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41918459/

相关文章:

java - Android - 将日期转换为时间前,但它返回 48 年前

javascript - 在 JavaScript 中从 Firebase 中删除特定 Node

android - 在Firebase-Realtime Database上使用什么规则让用户注册和登录?

ios - 更新到 Swift 3 后类型 'Any' 没有下标成员

ios - 带电子邮件密码的 FirebaseUI/Auth

android - ListView 显示重新扫描的蓝牙设备的重复条目

java - XML 解析器中出现此错误的原因是什么?

android - 无法在 Flutter 中使用 Firebase Auth 进行注册

javascript - 谷歌登录 : How to use redirect_uri in javascript api

android - 我将如何更改布局的背景