Removing Event Listeners
Making sure you remove event listeners is good for both correctness and garbage collection. Sometimes you don’t want (or need) to hear events any more and some times you just need to release references to aid the garbage collector in memory cleanup. Whatever your reason, there are a few ways to do it.
The basic call to removeEventListener is the simplest and, in practice, seems to get the most use:
clip.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
Here you need explicit knowledge of three things. You need to know the object you want to remove the event listener from, you need to know the type of event that you no longer want to hear, and you need to know the event listener you want to no hear the events with anymore. All three may be inconvenient to find, inconvenient to type, or totally uknown for various reasons. Let’s go through them in order.
Firstly, it may be inconvenient to get the object you want to remove the event listener from. This may seem absurd, but it’s not really. Consider this snippet of a class:
class Classy { private var __clip:MovieClip; private function onMouseDown(ev:MouseEvent): void { __clip.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); } }
Here we type __clip to reference the object we’d like to remove the event listener from. What if this event handler was servicing multiple clips? Imagine a dozen clips on the stage that, when clicked, disappear. We should clean up their event listeners, but we don’t want to have a dozen of such listeners just because we want to explicitly state the object we’re removing the event listener from. Here is a bit of convenience to get around this issue:
class Classy { private var __clip:MovieClip; private function onMouseDown(ev:MouseEvent): void { ev.target.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); } }
Here ev.target (or ev.currentTarget depending on circumstances) references the object that dispatched the event. This is of type Object, so our call to removeEventListener is dynamic and therefore much slower than the static call we used to have. In the vast majority of cases though this will not matter. We have freed ourselves of the need to write redundant event listeners.
Secondly, the event type. This should not be the concern of the event listener. The event listener only needs to know that it will be called when some logical event takes place. Here, the event listener knows it will be called when the mouse is down. It need not concern itself with the type of event that is dispatched when the mouse is pressed- that is the concern of the function that adds the event listener. So, here is a second refinement of the above:
class Classy { private var __clip:MovieClip; private function onMouseDown(ev:MouseEvent): void { ev.target.removeEventListener(ev.type, onMouseDown); } }
The Event class conveniently provides a getter for the type string of event. This allows us to achieve our above goals. The event listener no longer needs to know the type of event in order to remove itself as a listener. One big advantage of this is that if the event type string changes, you don’t need to concern yourself with the event listener.
Lastly, the callback itself. This I’ve discussed previously as being very handy when you are using dynamic functions. Feel free to peruse the previous article to learn more about that. As far as event listeners go though, here it is:
class Classy { private var __clip:MovieClip; private function onMouseDown(ev:MouseEvent): void { ev.target.removeEventListener(ev.type, arguments.callee); } }
Even in the case of a non-dynamic function like this one, you get a benefit. If you change the name of the function you don’t have to change what you’ve typed into the removeEventListener call. So, in summary I present to you the most dynamic way you can possibly remove an event listener:
ev.target.removeEventListener(ev.type, arguments.callee);
There are two downsides to this. The first I’ve already mentioned: ev.target is an Object and the removeEventListener call is therefore dynamic. The second is that the arguments variable is also dynamic, so the callee field access is also dynamic. This is one slow way to remove an event listener! Obviously this is not preferred for anything you might be doing many times per frame. However, if you’re doing much adding or removing event listeners every frame, you have bigger fish to fry.
#1 by Marko3Blokes on September 30th, 2010 ·
Awesome!
Just one thing; if you do ev.target could that potentially give you a reference to a child that caught the event instead of the thing that you attached the listener to? For example if I have movieclip1 and movieclip2 where movieclip2 is a child of movieclip1 – sometimes it will return movieclip2 as ev.target. Since I found out this was happening to me – I have been using ev.currentTarget.
Thanks for the great article!
#2 by jackson on September 30th, 2010 ·
That’s a good point: if you’re using this with any
DisplayObjects
then you’ll want to make sure you get the rightEventDispatcher
to remove from.