web-dev-qa-db-ja.com

Firebase Android onAuthStateChangedが2回呼び出されました

新しいFirebase SDKの使用を開始しました。

ユーザーログインを実行しているときに、onAuthStateChangedメソッドが同じ状態で2回呼び出されています(ユーザーのサインインなど)。

AuthStateListenerをFirebaseAuth参照に1回だけ追加すると確信しています。

何か助けは?

34
Adi

はい、これは非常に迷惑です。これは登録呼び出しによるものです。それだけでなく、onAuthStateChangedは多くの異なる状態で何度も呼び出され、どの状態であるかを知ることはできません。

Documentation は言う:

onAuthStateChanged(FirebaseAuth auth)

このメソッドは、認証状態の変化時にUIスレッドで呼び出されます。

  • リスナーが登録された直後

  • ユーザーがログインしているとき

  • 現在のユーザーがログアウトしているとき
  • 現在のユーザーが変更されたとき
  • 現在のユーザーのトークンに変更がある場合

ここでは、現在の状態を発見するためのいくつかのヒントを示します。

  • 登録呼び出し:フラグのある最初の呼び出しをスキップします。
  • ユーザーがサインインしました:パラメーターからのユーザーは!= nullです。
  • ユーザーがログアウトしました:パラメーターからのユーザーは== nullです。
  • 現在のユーザーの変更:パラメーターからのユーザーは!= nullで、最後のユーザーIDは!=パラメーターからのユーザーIDです。
  • ユーザートークンの更新:パラメーターからのユーザーは!= null、最後のユーザーIDは==パラメーターからのユーザーID

このリスナーは混乱し、非常にバグが発生しやすくなります。 Firebaseチームが調査する必要があります。

38
Fabricio

私の回避策は、グローバルに宣言されたブール値を使用して、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;
                }
            }
        }
    };
5
YYY

ここで提供されている他の答えはうまくいくかもしれませんが、フラグを管理するのは面倒で間違いがちです。

私はイベントを短時間でデバウンスすることを好みます。たとえば、ユーザーが200ミリ秒以内にログインしてからログアウトすることはほとんどありません。

[〜#〜] tldr [〜#〜]

Debouncingは、イベントを処理する前に、事前定義された期間内に同じイベントが再び発生するかどうかを確認するために待機することを意味します。もしそうなら、あなたはタイマーをリセットし、再び待ちます。そうでない場合は、イベントを処理します。

これはAndroid質問です。これは私の分野ではありませんが、きっとAndroidは、タスクに役立つ何らかの種類のツールを提供します。 、簡単なタイマーで作ることができます。

JavaScriptの実装は次のようになります。

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

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

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

        handleAuthStateChanged(auth);
    }, DebounceDueTime);
}

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

通常、私はリスナーを追加する前にUIをセットアップし、いつでもセットアップを繰り返します認証状態が変化します(最初の二重呼び出しを回避します)。私の解決策は、ブールフラグソリューションを拡張し、最後のユーザーのuid(トークンではない)を追跡することです。これはnullの場合があります。

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

onCreateでは、リスナーをonStartに追加する前に、認証インスタンスを取得し、それに応じてUIを設定します

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

ここで、getUserSetUIは、認証インスタンスに従って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();
    }
}
0
Danielozzo
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)を呼び出す必要があります

0
Rakshith Raj