web-dev-qa-db-de.com

Firebase Android onAuthStateChanged wurde zweimal aufgerufen

Ich arbeite mit dem neuen Firebase-SDK.

Wenn ich die Benutzeranmeldung durchführe, wird die onAuthStateChanged-Methode zweimal mit demselben Status aufgerufen (Benutzeranmeldung usw.).

Ich bin sicher, ich füge den AuthStateListener nur einmal zur FirebaseAuth-Referenz hinzu.

Irgendeine Hilfe?

26
Adi

Ja, und das ist sehr ärgerlich. Dies ist aufgrund eines Registrierungsaufrufs. Darüber hinaus wird onAuthStateChanged in vielen verschiedenen Status mehrmals aufgerufen, ohne dass man wissen kann, um welchen Status es sich handelt.

Dokumentation sagt:

onAuthStateChanged (FirebaseAuth-Authentifizierung)

Diese Methode wird im UI-Thread bei Änderungen des Authentifizierungsstatus aufgerufen:

  • Gleich nachdem der Listener registriert wurde

  • Wenn ein Benutzer angemeldet ist

  • Wenn der aktuelle Benutzer abgemeldet ist
  • Wenn sich der aktuelle Benutzer ändert
  • Wenn sich das Token des aktuellen Benutzers geändert hat 

Hier einige Tipps, um den aktuellen Stand zu erfahren:

  • Registrierungsanruf: Überspringen Sie den ersten Anruf mit einer Flagge.
  • Benutzer angemeldet: Benutzer von Parameter ist! = Null.
  • Benutzer abgemeldet: Benutzer von Parameter ist == null.
  • Aktuelle Benutzeränderungen: Benutzer von Parameter ist! = Null und letzte Benutzer-ID ist! = Benutzer-ID von Parameter 
  • Benutzer-Token-Aktualisierung: Benutzer von Parameter ist! = Null und letzte Benutzer-ID ist = Benutzer-ID von Parameter

Dieser Listener ist ein Durcheinander und sehr fehleranfällig. Das Firebase-Team sollte sich darum kümmern.

32
Fabricio

Meine Problemumgehung ist die Verwendung eines global deklarierten Booleschen Befehls, wenn onAuthStateChanged zuvor aufgerufen werden muss.

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;
                }
            }
        }
    };
5
YYY

Normalerweise möchte ich die Benutzeroberfläche vor dem Hinzufügen des Listeners einrichten und das Setup jedes Mal wiederholen, wenn sich der Auth-Status ändert (Vermeidung des ersten Doppelrufs). Meine Lösung besteht darin, die Boolesche Flag-Lösung zu verbessern und die UID (nicht das Token) des letzten Benutzers zu verfolgen, die null sein kann.

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

In onCreate rufe ich die Auth-Instanz ab und stelle die Benutzeroberfläche entsprechend ein, bevor der Listener in onStart hinzugefügt wird.

@Override
protected void onCreate(Bundle savedInstanceState){
    ...
    firebaseAuth = FirebaseAuth.getInstance();
    getUserSetUI();
    ...
}

wo getUserSetUI setzt lastUid gemäß der Auth-Instanz

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

Der Listener prüft, ob sich der Status tatsächlich geändert hat

@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();
    }
}
0
Danielozzo

Während die anderen hier gegebenen Antworten die Arbeit erledigen könnten, finde ich die Verwaltung einer Flagge umständlich und fehleranfällig.

Ich ziehe es vor, die Veranstaltung innerhalb kurzer Zeit zu entprellen. Es ist sehr unwahrscheinlich, vielleicht sogar unmöglich, dass sich ein Benutzer innerhalb von 200 ms an- und wieder abmeldet.

TLDR

Entprellen bedeutet, dass Sie vor der Bearbeitung eines Ereignisses warten, bis dasselbe Ereignis innerhalb eines festgelegten Zeitraums erneut ausgelöst wird. In diesem Fall setzen Sie den Timer zurück und warten erneut. Wenn nicht, übernehmen Sie das Ereignis.

Dies ist eine Android Frage, die nicht mein Fachgebiet ist, aber ich bin mir sicher Android bietet eine Art Tool, das bei der Aufgabe helfen kann. Wenn nicht können Sie eine mit einem einfachen Timer machen.

So könnte eine Javascript-Implementierung aussehen:

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

function onAuthStateChanged(auth)
{
    if (debounceTimeout)
        clearTimeout(debounceTimeout);

    debounceTimeout = timeout(() =>
    {
        debounceTimeout = null;

        handleEvent(auth);
    }, DebounceDueTime);
}

function handleAuthStateChanged(auth)
{
    // ... process event
}
0
Shy Agam