Firebase Android onAuthStateChanged 调用了两次

Posted

技术标签:

【中文标题】Firebase Android onAuthStateChanged 调用了两次【英文标题】:Firebase Android onAuthStateChanged called twice 【发布时间】:2016-10-07 00:24:09 【问题描述】:

我已经开始使用新的 Firebase SDK。

当我进行用户登录时,我的 onAuthStateChanged 方法被调用了两次,状态相同(等用户登录)。

我确定我只将 AuthStateListener 添加到 FirebaseAuth 参考中一次。

有什么帮助吗?

【问题讨论】:

你的代码在哪里? 我的代码中也存在这个问题。 onStart() 除了调用 super:FirebaseAuth.getInstance().addAuthStateListener(this); 之外只有这个代码。在其他任何地方都找不到这个调用,我检查了onStart() 只被调用了一次。然而,onAuthStateChanged(...) 方法被调用了两次(有时是三次)。 可能是一个错误,同时在此答案中使用标志:***.com/a/37686371/3597165 Firebase android onAuthStateChanged() fire twice after signInWithEmailAndPassword()的可能重复 9.4.0 中未修复 【参考方案1】:

虽然此处提供的其他答案可能会完成这项工作,但我发现管理标志很麻烦且容易出错。

我更喜欢在短时间内消除事件的抖动。假设用户在 200 毫秒内登录然后注销是非常不可能的,甚至是不可能的。

TLDR

去抖动意味着在处理事件之前,您等待查看相同的事件是否会在预定义的时间段内再次触发。 如果确实如此,则重置计时器并再次等待。 如果没有,则由您处理该事件。

这是一个 Android 问题,不是我的领域,但我确信 android 提供了某种可以帮助完成任务的工具。 如果没有,您可以使用一个简单的计时器制作一个。

以下是 javascript 实现的样子:

var debounceTimeout;
const DebounceDueTime = 200; // 200ms

function onAuthStateChanged(auth)

    if (debounceTimeout)
        clearTimeout(debounceTimeout);

    debounceTimeout = setTimeout(() =>
    
        debounceTimeout = null;

        handleAuthStateChanged(auth);
    , DebounceDueTime);


function handleAuthStateChanged(auth)

    // ... process event

【讨论】:

最佳解决方案恕我直言。希望我在写 if else 阶梯之前看到这个答案。哎呀。【参考方案2】:
  try
       FirebaseAuth.getInstance().signOut();
       FirebaseInstanceId.getInstance().deleteInstanceId();
   catch (Exception ex)
       ex.printStackTrace();
   

当用户从 gmail 注销时,该用户也应该从 firebase 注销。这就是我解决此问题的方法。

【讨论】:

【参考方案3】:
if (authStateListener == null) 
        authStateListener = new FirebaseAuth.AuthStateListener() 
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) 
                if (firebaseAuth.getCurrentUser() == null) 
                    //Do anything here which needs to be done after signout is complete
                    FirebaseAuth.getInstance().removeAuthStateListener(this);
                    Log.d(TAG_, "logout");


                    finish();
                 else 
                
            
        ;
    

应调用 FirebaseAuth.getInstance().removeAuthStateListener(this)

【讨论】:

【参考方案4】:

通常我想在添加侦听器之前设置 UI,并随时重复设置身份验证状态更改(避免初始双重调用)。我的解决方案是增强布尔标志解决方案并跟踪最后一个用户的 uid(不是令牌),它可能为 null。

private FirebaseAuth firebaseAuth;
private String lastUid; // keeps track of login status and changes thereof

onCreate 中,我获取 auth 实例并相应地设置 UI,然后在 onStart

中添加侦听器
@Override
protected void onCreate(Bundle savedInstanceState)
    ...
    firebaseAuth = FirebaseAuth.getInstance();
    getUserSetUI();
    ...

其中 getUserSetUI 根据 auth 实例设置 lastUid

private void getUserSetUI()
    lastUid = (firebaseAuth == null || firebaseAuth.getCurrentUser() == null) ?
            null : firebaseAuth.getUid();
    setUI(!(lastUid == null));

监听器检查状态是否真的改变了

@Override
public void onAuthStateChanged(@NonNull FirebaseAuth auth)
    String uid = auth.getUid(); // could be null
    if( (uid == null && lastUid != null) || // loggedout
            (uid != null && lastUid == null) || // loggedin
            (uid != null && lastUid != null && // switched accounts (unlikely)
                    !uid.equals(lastUid)))
        getUserSetUI();
    

【讨论】:

【参考方案5】:

我的解决方法是使用全局声明的布尔值来标记是否需要调用 onAuthStateChanged。

private Boolean authFlag = false;
 mAuthListener = new FirebaseAuth.AuthStateListener() 
        @Override
        public void onAuthStateChanged(@NonNull final FirebaseAuth firebaseAuth) 
            if (firebaseAuth.getCurrentUser() != null) 
                if(authFlag== false) 
                    // Task to perform once
                    authFlag=true;
                
            
        
    ;

【讨论】:

谢谢简单,但当您不想浪费更多时间时,可以完成工作。【参考方案6】:

是的,这很烦人。这是由于注册电话。不仅如此,onAuthStateChanged 还会在许多不同的状态下被多次调用,不可能知道它是哪个状态。

Documentation 说:

onAuthStateChanged(FirebaseAuth 身份验证)

当身份验证状态发生变化时,会在 UI 线程中调用此方法:

在监听器注册之后

当用户登录时

当前用户退出时

当当前用户改变时

当当前用户的令牌发生变化时

这里有一些发现当前状态的提示:

注册调用:跳过带有标志的第一个调用。 用户已登录:参数中的用户为 != null。 用户已退出:参数中的用户为 == null。 当前用户更改:参数中的用户为 != null 且最后一个用户 ID 为 != 参数中的用户 ID 用户令牌刷新:参数中的用户为 != null 且最后一个用户 ID 为 == 参数中的用户 ID

这个监听器很乱而且很容易出错。 Firebase 团队应该调查一下。

【讨论】:

我同意。此问题目前存在于 ios 上。感谢您为我们整理状态。 即使过了将近 5 年,问题依然存在......

以上是关于Firebase Android onAuthStateChanged 调用了两次的主要内容,如果未能解决你的问题,请参考以下文章

如何归功于 Firebase 和 Android 支持库?

使用 Android Firebase 堆栈推送通知

从firebase检索数据到android

Android使用Firebase

在 Android 中启用 Firebase 崩溃报告

通过电子邮件/密码使用 Firebase 身份验证将 Firebase 连接到 Android 应用程序