Подтвердить что ты не робот

Firebase Android onAuthStateChanged вызывается дважды

Я начал работать с новым Firebase SDK.

Когда я выполняю вход пользователя в систему, я использую метод onAuthStateChanged дважды с тем же состоянием (и т.д. пользовательский вход).

Я уверен, что добавляю AuthStateListener только один раз к ссылке FirebaseAuth.

Любая помощь?

4b9b3361

Ответ 1

Да, и это очень раздражает. Это связано с регистрационным звонком. Не только это, onAuthStateChanged будет вызываться много раз во многих разных состояниях, не имея возможности узнать, в каком состоянии оно находится.

Документация говорит:

onAuthStateChanged (FirebaseAuth auth)

Этот метод вызывается в потоке пользовательского интерфейса при изменении состояния аутентификации:

  • Сразу после регистрации слушателя

  • Когда пользователь подписывается

  • При выводе текущего пользователя
  • При изменении текущего пользователя
  • При изменении текущего токена пользователя

Вот несколько советов по обнаружению текущего состояния:

  • Регистрационный вызов: пропустите первый вызов с флагом.
  • Пользователь выполнил вход: пользователь из параметра:!= null.
  • Пользователь отключен: пользователь из параметра == null.
  • Текущие пользовательские изменения: пользователь из параметра is!= null, а последний идентификатор пользователя: = идентификатор пользователя из параметра
  • Обновление токена пользователя: пользователь из параметра: = null, а последний идентификатор пользователя - id пользователя из параметра

Этот слушатель является беспорядком и очень ошибкой. Команда Firebase должна изучить ее.

Ответ 2

Мое обходное решение заключается в том, чтобы использовать флаг Boolean, объявленный глобально, для флага, если раньше требовалось 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;
                }
            }
        }
    };

Ответ 3

Обычно я хочу настроить интерфейс перед добавлением прослушивателя и повторять настройку каждый раз, когда изменяется состояние аутентификации (избегая первоначального двойного вызова). Мое решение состоит в улучшении решения с использованием логического флага и отслеживании идентификатора пользователя (не токена) последнего пользователя, который может быть нулевым.

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

В onCreate я получаю экземпляр auth и соответственно устанавливаю пользовательский интерфейс перед добавлением слушателя в onStart

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

Ответ 4

В то время как другие ответы, представленные здесь, могли бы справиться с работой, я нахожу управление флагом громоздким и подверженным ошибкам.

Я предпочитаю разоблачать событие в короткие сроки. Очень маловероятно, может быть, даже невозможно, чтобы пользователь вошел в систему, а затем вышел из системы в течение 200 мс, скажем.

TLDR

Отмена означает, что перед обработкой события вы должны подождать, чтобы выяснить, произойдет ли то же событие снова в течение заданного периода времени. Если это так, вы сбрасываете таймер и ждете снова. Если это не так, вы обрабатываете событие.

Это вопрос 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
}