Update: My bug report has been marked Not a Bug by Adobe. As Joeri mentions in this post’s comments, and Charles Liss explains in the bug report comments, Flash Player makes a copy of the event listeners internally when dispatchEvent()
is called. It’s by design that a call to removeEventListener()
will affect the original list of listeners, but it will not affect the copied list. I followed up with a request to describe this behavior in the API documentation so that others who run into the same weird behavior might have a better chance of learning why Flash Player seems to be behaving incorrectly.
I’ve been struggling off and on for days trying to figure out why a certain display object that I’d been fading in and out sometimes got stuck with partial visibility. Even when I explicitly set the alpha
value to 0.0
or 1.0
after removing the animation and all its listeners, there was still the occasional situation where it would clearly receive a different value. I finally tracked down the following bug in Flash Player. If two functions are subscribed to the same event type from the same event dispatcher, and the first listener removes the second listener, the second listener is still called by Flash Player.
The following class demonstrates the problem.
package { import flash.display.Sprite; import flash.events.Event; import flash.events.EventDispatcher; public class EventErrorTest extends Sprite { public static var dispatcher:EventDispatcher = new EventDispatcher(); public function EventErrorTest() { dispatcher.addEventListener(Event.COMPLETE, dispatcherComplete1Handler); dispatcher.addEventListener(Event.COMPLETE, dispatcherComplete2Handler); dispatcher.dispatchEvent(new Event(Event.COMPLETE)); dispatcher.dispatchEvent(new Event(Event.COMPLETE)); } private function dispatcherComplete1Handler(event:Event):void { dispatcher.removeEventListener(Event.COMPLETE, dispatcherComplete2Handler); trace("1"); } private function dispatcherComplete2Handler(event:Event):void { trace("2"); } } }
The expected output is as follows:
1
1
Instead, my output console displays this instead:
1
2
1
Clearly, the second listener is still called the first time the event is dispatched. If you move the call to removeEventListener()
to the line before the first call to dispatchEvent()
, the output appears as expected.
I discovered this bug while using Grant Skinner’s excellent GTween library for AS3 in the current game I’ve developing. In my game, certain animations may be paused following the completion of other animations. Since (internally) all GTween instances listen to a static timing object, pausing a GTween inside an event listener attached to another GTween causes the supposedly-paused GTween to update the target’s properties one last time.
If you happen to be using GTween, and you encounter this same issue, adding the following line at the beginning of handleTick()
in GTween.as should fix the problem:
if (_paused) return;
This event bug has been filed in Adobe’s public Flash Player database. You’re welcome to vote for it.