Quickstart-android: AuthStateListener is called multiple times.

Created on 8 Jul 2016  ·  17Comments  ·  Source: firebase/quickstart-android

  • Android device: Sony D6503
  • Android OS version: 4.4.4
  • Google Play Services version: 9.2.56(038-124593566)
  • Firebase/Play Services SDK version: 9.0.2

    Describe the problem:

AuthStateListener is called multiple times.

Steps to reproduce:

  1. addAuthStateListener onStart activity
  2. removeAuthStateListener onStop activity

    Observed Results:

07-08 23:36:16.804 29229-29229/com.domain D/FirebaseApp: Notifying auth state listeners.
07-08 23:36:16.804 29229-29229/com.domain D/FirebaseApp: Notified 0 auth state listeners.
07-08 23:36:16.814 29229-29229/com.domain D/FirebaseApp: Notifying auth state listeners.
07-08 23:36:16.814 29229-29229/com.domain D/FirebaseApp: Notified 0 auth state listeners.

Expected Results:

07-08 23:36:16.804 29229-29229/com.domain D/FirebaseApp: Notifying auth state listeners.
07-08 23:36:16.804 29229-29229/com.domain D/FirebaseApp: Notified 0 auth state listeners.

Most helpful comment

Firebase: Hey, there are changes on the user's auth state.
Devs: Ok. Cool. What is it?
Firebase: You don't need to know. It's only matter for us.
Devs: Ow... Ok. See you later.
... in just one second (or even less?)...
Firebase: Hey, there are changes on the user's auth state.
Devs: Ok. Cool. What is it now?
Firebase: You don't need to know. It's only matter for us.
Devs: ....

Seriously. Us developers only need to know when user is signed in, refreshed tokens (if any) and signed out. And that's basically it. And yet the library spamming us with too many changes that they deem it unnecessary for us. If it unnecessary for us, then why bother informing us (by triggering that event in rapid succession)? Isn't this just hogging down the app performance?

All 17 comments

@mific I can confirm that this is happening, not 100% sure why but I will find out. In the meantime, what problem is this causing for you? Maybe we can find a workaround.

Just heard back, this is the intended behavior. We notify listeners once per internal events, so in this case it was likely a TOKEN_CHANGE event followed by a USER_INFO_CHANGE event. Unfortunately we don't expose event type via the SDK so if this is bothering you, I'd suggest keeping track of a timestamp and ignoring events that are too close to each other,

Thanks for your comments. I added additional checks. Where i can see full list of internal evens for FirebaseAuth.AuthStateListener?

@mific we don't publish such a list since it should not matter to your app. You should only react to the information passed to the listener.

I can reproduce the same issue. onAuthStateChanged is called between 4 to 16 times.

Any resolutions for this so far?

Hi. I have the same issue
In AuthStateListener I am trying to get the auth token. Tokens are fetched multiple times and have a different values sometimes. After installed proxy I saw:

   POST https://securetoken.googleapis.com/v1/token?key=AIzaSyB9NSGc-0E5BDPQaOX3IRWCo2T...
        ← 200 application/json 1.01kB 282ms
   POST https://securetoken.googleapis.com/v1/token?key=AIzaSyB9NSGc-0E5BDPQaOX3IRWCo2T...
        ← 200 application/json 1.01kB 287ms
   POST https://securetoken.googleapis.com/v1/token?key=AIzaSyB9NSGc-0E5BDPQaOX3IRWCo2T...
        ← 200 application/json 1.01kB 277ms
   POST https://securetoken.googleapis.com/v1/token?key=AIzaSyB9NSGc-0E5BDPQaOX3IRWCo2T...
        ← 200 application/json 1.01kB 289ms
   POST https://securetoken.googleapis.com/v1/token?key=AIzaSyB9NSGc-0E5BDPQaOX3IRWCo2T...
        ← 200 application/json 1.01kB 320ms
   POST https://securetoken.googleapis.com/v1/token?key=AIzaSyB9NSGc-0E5BDPQaOX3IRWCo2T...
        ← 200 application/json 1.01kB 296ms

How prevent this unsatisfied behavior?
I cant store the first token permanently because expiration time is not known
It seems the knowledge about the internal event types would be not superfluous

@ramonz what sort of issues is this causing in your application? Ideally when using the Firebase Android SDKs you should not need to worry about tokens at all.

I can confirm that this is happening. We should either get a reason for the change, or get only one change. An authentication state change to a developer means either the user has signed in, or has signed out.

I use the auth listener callback to detect whether there is already an opened session.
It works perfectly, so i thought. Now i am faced with a device on which that callback is triggered on app start telling me that there is a signed in user. It does so after a fresh install of an app (or data/cache clear). Further that UID seems to not exist. I cant find it in the Firebase Web interface.

that exprrience is based on a custom app and not the quckstart sample. I did not test the sample with that 'problematic' device yet

I'm getting three calls all at the same time

09-23 14:15:52.584 28961-28961/com.gpease.one D/FirebaseApp: Notifying auth state listeners.
09-23 14:15:52.585 28961-28961/com.gpease.one D/FirebaseApp: Notified 0 auth state listeners.
09-23 14:15:52.585 28961-28961/com.gpease.one D/SignInActivity: onAuthStateChanged:signed_in:vGEYuxs3VTXKnfQ94xXs2m3ZJlE3
09-23 14:15:52.597 28961-28961/com.gpease.one D/FirebaseApp: Notifying auth state listeners.
09-23 14:15:52.598 28961-28961/com.gpease.one D/FirebaseApp: Notified 0 auth state listeners.
09-23 14:15:52.598 28961-28961/com.gpease.one D/SignInActivity: onAuthStateChanged:signed_in:vGEYuxs3VTXKnfQ94xXs2m3ZJlE3
09-23 14:15:52.607 28961-28961/com.gpease.one D/SignInActivity: onAuthStateChanged:signed_in:vGEYuxs3VTXKnfQ94xXs2m3ZJlE3

I believe the intended behavior of the onAuthStateChanged should be what it's name says: fire only when auth state has actually changed. Telling us to just check timestamps and ignore events that are close together is just a workaround.

Would love to see a proper fix.

For me my listener getting called one extra time on every signout. I found that it is actually the onCreate() of my activity that getting called more and more. I wonder if Firebase is the cause of this, as seen here using AsyncTask's can cause issues like this where onCreate() is fired multiple times. http://stackoverflow.com/a/22224038/804440

Firebase: Hey, there are changes on the user's auth state.
Devs: Ok. Cool. What is it?
Firebase: You don't need to know. It's only matter for us.
Devs: Ow... Ok. See you later.
... in just one second (or even less?)...
Firebase: Hey, there are changes on the user's auth state.
Devs: Ok. Cool. What is it now?
Firebase: You don't need to know. It's only matter for us.
Devs: ....

Seriously. Us developers only need to know when user is signed in, refreshed tokens (if any) and signed out. And that's basically it. And yet the library spamming us with too many changes that they deem it unnecessary for us. If it unnecessary for us, then why bother informing us (by triggering that event in rapid succession)? Isn't this just hogging down the app performance?

this behaviour makes using firebase for my case pretty useless. so annoying and time wasting because you need to add different variables to track extra state of the app. Also because how could we know when exactly those events are triggered and what is minimum delta time between them?

To me, it seems that this is the same architecture as callbacks for event listeners. As per documentation, they are called twice, once they are created and once when the data changes. Seems that this follows the same pattern.
My workaround is that I introduced a static boolean value that tracks if firebase auth has executed its operation the first time.

My authStateListener looks like this:

private FirebaseAuth.AuthStateListener authStateListener = new FirebaseAuth.AuthStateListener() {
    @Override
    public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {

        if (!isFirebaseCalledOnce) {

            isFirebaseCalledOnce = true;
            FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
            if (firebaseUser == null)
                startActivityForResult(AuthUI.getInstance()
                        .createSignInIntentBuilder()
                        .setProviders(Arrays.asList(new AuthUI.IdpConfig.Builder(AuthUI.EMAIL_PROVIDER).build(),
                                new AuthUI.IdpConfig.Builder(AuthUI.GOOGLE_PROVIDER).build(),
                                new AuthUI.IdpConfig.Builder(AuthUI.FACEBOOK_PROVIDER).build(),
                                new AuthUI.IdpConfig.Builder(AuthUI.TWITTER_PROVIDER).build()))
                        .setLogo(R.drawable.ic_splash)
                        .setTheme(R.style.SplashThemeBase)
                        .build(), AUTH_REQ);
            else
                processUserState();

        }

    }

};

It used to cause the processing of user state to run twice, which meant creating the same activity twice.

Call the removeAuthStateListener after you send the intent/ action
private FirebaseAuth.AuthStateListener mAuthListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { if(firebaseAuth.getCurrentUser() == null){ startActivity(new Intent(MainActivity.this, LoginActivity.class)); finish(); mAuth.removeAuthStateListener(mAuthListener); } } };

Was this page helpful?
0 / 5 - 0 ratings