Невозможно удалить ValueEventListener, установленный для одного значения и без тайм-аута в Firebase DB - PullRequest
0 голосов
/ 02 августа 2020

При использовании addListenerForSingleValueEvent было бы неплохо добавить таймаут к этой операции. Поскольку Firebase, похоже, этого не хватает, я решил реализовать это самостоятельно. Однако я обнаружил, что не могу удалить этих слушателей. Вызов removeEventListener не работает. Они по-прежнему срабатывают всякий раз, когда Firebase устанавливает соединение с сервером. Можно обработать это логически внутри onDataChanged, но это становится очень и очень сложным, когда эти события возникают неожиданно и полностью вне контекста. Кто-нибудь знает чистый способ справиться с этим?

Код: Я устанавливаю и удаляю слушатель немедленно. Через некоторое время включите inte rnet - вызывается onDataChanged.

        DatabaseReference ref = db.getReference("blablalba");
        oneshotlistener = new ValueEventListener()
        {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot)
            {
                Log.v("FIREBASE LISTEN", "ONE SHOT LISTENER TRIGGERED");
                if (snapshot.exists())
                {
                    String s = snapshot.getValue(String.class);
                    Log.v("FIREBASE LISTEN", "RESULT: " + s);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error)
            {
                Log.v("LISTEN", "DB FAIL");
            }
        };
        ref.addListenerForSingleValueEvent(oneshotlistener);
        ref.removeEventListener(oneshotlistener);   //remove immediately for test

1 Ответ

0 голосов
/ 02 августа 2020

Быстрое изучение кода addListenerForSingleValueEvent показывает, почему это не удается:

Firebase добавляет свой собственный прослушиватель событий, который удаляется при вызове onDataChanged. Таким образом, в addListenerForSingleValueEvent нет ничего особенного, и я предполагаю, что мы можем обойти проблему таким способом (используя обычный addValueEventListener):

DatabaseReference ref = db.getReference("blabla");
        oneshotlistener = new ValueEventListener()
        {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot)
            {
                snapshot.getRef().removeEventListener(this);
                Log.v("FIREBASE LISTEN", "ONE SHOT LISTENER TRIGGERED");
                if (snapshot.exists())
                {
                    String s = snapshot.getValue(String.class);
                    Log.v("FIREBASE LISTEN", "RESULT: " + s);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error)
            {
                Log.v("LISTEN", "DB FAIL");
            }
        };
        ref.addValueEventListener(oneshotlistener);
        ref.removeEventListener(oneshotlistener);    //remove immediately for test

Тесты подтверждают, что слушатель никогда не запускается. Теперь можно разработать процедуру тайм-аута, чтобы удалить слушателя и вызвать ошибку. Также слушатель может быть удален в onPause (), поэтому неожиданные события onDataChanged не возникают, если приложение приостановлено / возобновлено. Тем не менее, было бы неплохо, если бы в Firebase была встроена эта функция. Имейте функцию, которая позволяет устанавливать тайм-аут прослушивания в миллисекундах, а для слушателей, зарегистрированных с помощью addListenerForSingleValueEvent, есть дополнительный вызов интерфейса, например:

        db.setTimeout(ms);

        DatabaseReference ref = db.getReference("blablalba");
        oneshotlistener = new ValueEventListener()
        {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot)
            {
                Log.v("FIREBASE LISTEN", "ONE SHOT LISTENER TRIGGERED");
                if (snapshot.exists())
                {
                    String s = snapshot.getValue(String.class);
                    Log.v("FIREBASE LISTEN", "RESULT: " + s);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error)
            {
                Log.v("LISTEN", "DB FAIL");
            }

            @Override
            public void onTimeout()
            {
                Log.v("LISTEN", "OP TIMEDOUT");
                //take action
            }
        };
        ref.addListenerForSingleValueEvent(oneshotlistener);
...