代码之家  ›  专栏  ›  技术社区  ›  Steven Mercatante Dimitri Kopriwa

为什么我的事件监听器会多次开火?

  •  1
  • Steven Mercatante Dimitri Kopriwa  · 技术社区  · 14 年前

    在我的flash项目中,我有一个movieclip,它有两个关键帧。两帧都包含一个movieclip。

    框架1 Landing
    框架2 Game

    应用程序的流程很简单:

    1. 用户到达登录页(第1帧)
    2. 用户点击“开始游戏”按钮
    3. 用户被带到游戏页面(第2帧)
    4. 游戏结束后,用户可以按“再次播放”按钮返回到步骤1。

    两个 着陆 游戏 movieclips链接到定义事件侦听器的单独类。问题是,当我玩完游戏回到第一步时, 游戏 事件侦听器为各自的事件触发两次。如果我第三次经历这个过程,事件监听器会为每个事件触发三次。这一直在发生,所以如果我循环应用程序流7次,事件侦听器将触发7次。我不明白为什么会这样,因为在第1帧, 游戏 movieclip(我假设它的相关类实例)不存在——但我显然在这里遗漏了一些东西。

    我在其他项目中也遇到过这个问题,尝试通过首先检查事件监听器是否存在并仅在不存在的情况下定义它们来解决它,但最终得到的意外结果并不能真正解决问题。

    我需要确保事件侦听器只触发一次。任何建议和见解都将非常感谢,谢谢!

    2 回复  |  直到 14 年前
        1
  •  2
  •   typeoneerror    14 年前

    如果在同一层上有两个具有不同剪辑的帧,则每次该帧“进入”时,都会创建该剪辑。当它“离开”时,夹子会被移除,但它仍然会保留在周围,不会被垃圾收集。所以下次帧进入不同的剪辑时,它会被“创建”并得到自己的侦听器。您最好的办法是在更改帧时删除侦听器。我通常通过让一个听众 Event.REMOVED_FROM_STAGE 在每堂课上。如果它被删除,那么您将清理其余的侦听器。

    你也可以尝试“弱听众”:

    addEventListener(GameEvent.GAME_START, gameStartedHandler, false, 0, true);
    

    “true”使链接“弱”,因此如果对象被移除,垃圾收集器可以将其拾取。但我不会完全依赖这个。最好手动删除引用,这样您就可以确定了。

    当然,这个答案假设很多。如果您发布代码/屏幕截图/flas以更好地诊断,这将很有帮助。

        2
  •  2
  •   marc_s    6 年前

    如果没有看到代码或者不知道你在听什么事件,不知道是谁/是什么激发了代码,就很难确定。

    但是,我的猜测是movieclips没有被收集(这不一定是内存泄漏!)所以,他们还活着,还在踢。可以说,您应该有一个方法将它们设置为“空闲”状态。也就是说,删除监听器、停止计时器等。其目的是使对象处于不运行任何代码的状态。

    movieclips和其他显示对象的一个简单方法,通常已经足够好了,就是监听添加到\阶段的内容,并从\阶段事件中删除。这里的想法是当你的对象被添加到舞台上时“激活”,在你的情况下,当你达到游戏类的第2帧时,它会“停用”,当它被移除时,也就是当你回到第1帧时。

    沿着这些线的东西:

    public class Game extends MovieClip {
    
        private var _timer:Timer;
    
        public function Game() {
            addEventListener(Event.ADDED_TO_STAGE,init);
            addEventListener(Event.REMOVED_FROM_STAGE,destroy);
        }
    
        private function init():void {
            //  your init code goes here
            //  just an example:
            _timer = new Timer(33);
            _timer.addEventListener(TimerEvent.TIMER,mainLoop);
            _timer.start();
            trace("init");
        }
    
        private function destroy():void {
            _timer.stop();
            _timer.removeEventListener(TimerEvent.TIMER,mainLoop);
            trace("destroy");
        }
    
        private function mainLoop(e:TimerEvent):void {
            //  code for main loop here...
            trace("mainLoop");
        }
    }
    

    检查跟踪是否正常工作。你应该看到“init”被追踪出来,然后“mainloop”,只要你停留在第2帧,当你回到第1帧时“销毁”。mainloop”应该在此时停止跟踪。

    除此之外,您可能还需要检查是否没有内存泄漏(事实上,您有7个实例并不一定意味着您有一个泄漏;但在某些情况下,如果GC运行,则至少应释放其中一些实例;如果从未发生这种情况,则是泄漏的症状;尝试强制GC查看活动实例的数量是否下降;如果不是,很可能是你漏了。