Java 事件侦听器在被删除后侦听

Java 事件侦听器在被删除后侦听,java,android,firebase,firebase-realtime-database,Java,Android,Firebase,Firebase Realtime Database,我班上有很多事件侦听器,早些时候我问过如何在这些侦听器发生一次后杀死它们,我已经解决了这个问题 它在某些情况下有效,但在另一些情况下我有问题。例如,我有一个具有事件侦听器的方法 private void startGame() { HomePage.getCurrentGameID(new HomePage.CallbackID() { @Override public void onSuccess(final String currentGame

我班上有很多事件侦听器,早些时候我问过如何在这些侦听器发生一次后杀死它们,我已经解决了这个问题

它在某些情况下有效,但在另一些情况下我有问题。例如,我有一个具有事件侦听器的方法

    private void startGame() {
    HomePage.getCurrentGameID(new HomePage.CallbackID() {
        @Override
        public void onSuccess(final String currentGameID) {
            games.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    if (dataSnapshot.child(currentGameID).getValue().equals(1)) {
                        getResults();
                        Log.i("FlipCoin", "``startGame() happened");
                    } else {
                        return;
                    }
                    games.removeEventListener(this);
                }
}
我有启动游戏的方法,在
onDataChange()
结束时,我有
games.removeEventListener(这个)
。但是有时候,即使在执行了这个之后,它仍然会运行代码,我知道这一点,因为每次该方法发生时,它都会记录到LogCat

我的代码中只有一个实例调用了
startGame()
,该实例就在这个计时器中

private void runCounter() {
    final Runnable counter = new Runnable() {
        @Override
        public void run() {
                Log.i("FlipCoin", "``runCounter() happened");
                startGame();
            }
        }
    };
    counter.run();
}
我去掉了许多不必要的代码,因此这些方法可能没有太多实际意义,但它们正被用作解决我的问题的示例

无论如何,正如您在runCounter()方法中所看到的,它会像应该的那样调用
startGame()
,并且我在该方法中还有一个日志,可以让我知道何时调用此
runCoutner()
方法

奇怪的是
runCounter()
方法在logcat中只记录了一次,但它一直记录
startGame()
,即使我在代码中只调用了一次,并且在方法的末尾删除了侦听器

为什么会发生这种事,我超级困惑


我正在使用的Runnable(与问题无关)


你用错了


如果只想侦听该值一次,然后删除侦听器,请使用:
addListenerForSingleValueEvent

,您可能应该在
addValueEventListener
之前添加日志,以了解它是否被多次添加。根据此代码,如果
removeEventListener
实现正确,则不应发生这种情况。为什么不使用
addListenerForSingleValueEvent
,其全部目的是只侦听一次?而且完全不需要在运行计数器中运行。如果你只调用startName(),你会得到完全相同的效果。@DougStevenson将其转换为
addListenerForSingleValueEvent
,会出现一些问题,如果你仔细阅读了我的帖子,你就会知道我去掉了代码来简化问题,Runnable确实有一个目的。我很好奇这个Runnable的实际用途是什么,现在它的行为与根本没有它相比。您通常只将Runnable与新线程、某个线程池或执行器结合使用。我也很好奇为什么addListenerForSingleValueEvent不适合您,因为它是SDK的核心功能。如果你正确使用它,它应该不会有问题。这意味着你的代码不止一次地调用这个方法。我的代码中只有一个点,我已经看过很多次了,这个方法被调用了。调用该方法的Runnable也只被调用一次。代码中只有一个调用并不意味着代码不会被多次调用。。。你可以开始组织你的代码,这比你最终会发现的bug还要混乱。您创建了许多可运行的
并在同一个线程中执行它们。。。这是毫无意义的。创建不必要的注释性类是一种糟糕的做法。另外,对于
新主页.CallbackID()
的作用没有任何解释。。。您使用
get
方法并将某个内容作为参数传递。。。这是一个基本的代码设计,如果你仍然无法理解为什么要多次调用,简单的调试,看看堆栈跟踪哪个方法在调用它,就像我在我的帖子中说的,我拿出了很多代码只是为了将问题简化到核心。所有看起来毫无意义的代码实际上都不是毫无意义的。
private void runCounter() {
    final TextView headsOrTails = findViewById(R.id.HeadsOrTails);
    final Handler handler = new Handler();
    final AtomicInteger n = new AtomicInteger(3);
    final Runnable counter = new Runnable() {
        @Override
        public void run() {
            headsOrTails.setText("Flipping in: " + Integer.toString(n.get()) + " seconds");
            if (n.getAndDecrement() >= 1)
                handler.postDelayed(this, 1000);
            else {
                headsOrTails.setText("Flipping");
                Log.i("FlipCoin", "``runCounter() happened");
                startGame();
            }
        }
    };
    counter.run();
}