Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Android onAuthStateChanged called twice

I've start working with new Firebase SDK.

When I'm doing user login, I'm onAuthStateChanged method is being called twice with same state (etc. user sign in).

I'm sure I'm adding the AuthStateListener only once to the FirebaseAuth reference.

Any help?

like image 375
Adi Avatar asked Jun 07 '16 07:06

Adi


3 Answers

Yes, and this is very annoying. This is due a registration call. Not only that, onAuthStateChanged is going to be called many times in many different states, with no possibility of knowing which state it is.

Documentation says:

onAuthStateChanged(FirebaseAuth auth)

This method gets invoked in the UI thread on changes in the authentication state:

  • Right after the listener has been registered

  • When a user is signed in

  • When the current user is signed out

  • When the current user changes

  • When there is a change in the current user's token

Here some tips to discover the current state:

  • Registration call: skip the first call with a flag.
  • User signed in: user from parameter is != null.
  • User signed out: user from parameter is == null.
  • Current user changes: user from parameter is != null and last user id is != user id from parameter
  • User token refresh: user from parameter is != null and last user id is == user id from parameter

This listener is a mess and very bugprone. Firebase team should look into it.

like image 71
Fabricio Avatar answered Nov 14 '22 04:11

Fabricio


While the other answers provided here might do the job, I find managing a flag cumbersome and error-prone.

I prefer debouncing the event within short periods of time. It is very unlikely, maybe even impossible, for a user to login then logout within a period of 200ms let's say.

TLDR

Debouncing means that before handling an event, you wait to see if the same event is gonna fire again within a predefined period of time. If it did, you reset the timer and wait again. If it didn't, you handle the event.

This is an Android question, which is not my field, but I'm sure android provides some kind of tool that can help with the task. If not, you can make one using a simple timer.

Here's how a Javascript implementation might look like:

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
}
like image 9
Shy Agam Avatar answered Nov 14 '22 03:11

Shy Agam


My workaround is to use a Boolean declared globally to flag if onAuthStateChanged has need called before.

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;
                }
            }
        }
    };
like image 8
YYY Avatar answered Nov 14 '22 03:11

YYY