Tuesday, April 22, 2008

Slide shows and duplicate event listeners in Adobe Flash ActionScript 3

Today was my first day (of 30) as an Adobe flash developer. I focused on trying to help one of my co-workers who is an avid PhotoShop / CS2 user try to get up to speed on getting a basic slide show build in Flash with ActionScript 3.

Most of the tutorials you find on the net assume ActionScript 2, so that's a handicap from the get go. We did eventually find something that got us going... until the bug made itself obvious in the first 2 minutes... we were getting multiple presses out of our Next button if we dared go back to the first frame of the slide show. Then we noticed it happened with the back button as well.

The code looked like this:

stop(); // stop the slide show at the first frame

Next_btn.addEventListener(
MouseEvent.MOUSE_UP,
function(evt:MouseEvent):void { nextFrame(); });

Back_btn.addEventListener(
MouseEvent.MOUSE_UP,
function(evt:MouseEvent):void { prevFrame(); });


Which works... unless you happen to get back to the first frame, because it runs again every time you happen to touch the first frame. There doesn't appear to be any way to put Initialization code before all of the run time code, so you have to work around this (and this page is probably where you'll learn about this if you're having this problem in the future, and not Adobe's help files)...

To prevent duplicate event handlers, it's necessary to wrap them in code, each and every time, to prevent this.

Something like this:

stop(); // stop the slide show on the first frame

if (! Next_btn.hasEventListener(MouseEvent.MOUSE_UP))(
Next_btn.addEventListener(MouseEvent.MOUSE_UP,function(evt:MouseEvent):void { nextFrame(); }));

if (! Back_btn.hasEventListener(MouseEvent.MOUSE_UP))(
Back_btn.addEventListener(MouseEvent.MOUSE_UP,function(evt:MouseEvent):void { prevFrame(); }));

It seems to be quite a waste to me... perhaps someone has a more elegant way of initializing things to avoid having to add all of this code, and force it to only execute once per application?

I'm glad to have figured it out and got things working today, so now I can sleep. Hopefully this will help at least one other person who is frustrated with duplicate events firing from addEventListener messing up things.

2 comments:

Flexy said...

You can avoid all of the issues mentioned above by passing a qualified method as the listener, rather than the dynamic function you're using.

i.e.

Next_btn.addEventListener( MouseEvent.MOUSE_UP, goNextFrame );
Back_btn.addEventListener( MouseEvent.MOUSE_UP, goPrevFrame );

function goNextFrame( e:MouseEvent ) :void
{
nextFrame();
}

function goPrevFrame( e:MouseEvent ) :void
{
prevFrame();
}


By doing that you avoid any chance of listener duplication and avoid having to use hasEventListener

G. said...

Hey, I don't know who you are but your post totally saved my keister!

I've been working all day to figure out how deal with a duplicate addEventListener issue. I consider myself a pretty advanced AS3 coder...but this thing totally killed me.

Until I found your blog! Kudos! Good Karma coming your way!

g.