Method of removing all event listeners
So over the weekend I was talking to a buddy of mine in regards to different ways of removing event listeners from objects. The way that I usually do it is that everything that requires a listener is placed in a “addListeners” method and and its counter part is placed in a “removeListeners” method. That’s a very simple way of doing it. It works all the time as long as you are on top of every single object that requires having a listener added and you place it on both functions.
Don’t get me wrong, that work around works pretty good but becomes sort of a drag at times (eh, call me lazy) so I came up with a more automated way of doing it! A little disclaimer though, the method that I am about to describe works in 99.9% of my cases because all my classes extend an abstract class of some sort. Anyway, let me show you how I go about it:
What I do is archive all the added listeners and then remove them later in a loop. Everything is done at the abstract class level
I then override the “addEventListener” method in order to push references into the array as so:
{
super.addEventListener(type, listener, useCapture, priority, useWeakReference);
arrListeners.push({type:type, listener:listener});
}
Now that you have a way to reference the added listeners, you would loop through the array to remove the listeners which still exist when needed:
{
for(var i:Number = 0; i<arrListeners.length; i++){
if(this.hasEventListener(arrListeners[i].type){
this.removeEventListener(arrListeners[i].type, arrListeners[i].listener);
}
}
arrListeners = null
}
That’s basically it. After that, if the object does not extend a class with that method, then I would just use the first method mentioned above.
You can download a quick example here. If you guys have any other ways of doing it, or can enhance the way that I am doing it now, please do let me know. Hope this helps!
Hy Reyco1,
I´ve done the exact same thing you did with this abstract class, but I came across another problem. Like you mentioned in you example the stage didnt registered it´s events since you can not override stage eventdispatcher.
And it would be also hard to manage the events from objects like sound, video, loader and so on.
So I´ve done a class similar to yours but I pass the obj that will dispatch the events. It´s something like this:
THE CLASS:
{
import flash.events.EventDispatcher;
/**
* ...
* @author ...
*/
public class EventHandler extends EventDispatcher
{
private var eventList:Array;
private var _dispatcher:*;
public function EventHandler(dispatcher:*)
{
eventList = new Array();
_dispatcher = dispatcher;
}
override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = true):void
{
eventList.push( { TYPE:type, LISTENER:listener } );
if (_dispatcher.hasEventListener(type))
{
_dispatcher.removeEventListener(type, listener);
}
_dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
}
public function RemoveEvent(type:String):void
{
var total:int = eventList.length ;
for (var i:int = 0; i < total; i++)
{
if (eventList[i].TYPE == type)
{
_dispatcher.removeEventListener(eventList[i].TYPE, eventList[i].LISTENER);
eventList.splice(i, 1);
total = eventList.length;
}
}
}
public function RemoveEvents():void
{
var total:int = eventList.length ;
for (var i:int = 0; i < total; i++)
{
_dispatcher.removeEventListener(eventList[i].TYPE, eventList[i].LISTENER);
}
eventList = [];
}
}
}
HOW TO:
{
import flash.display.Graphics;
import flash.display.MovieClip;
import flash.events.MouseEvent;
/**
* ...
* @author ...
*/
public class Main extends MovieClip
{
private var boxSample:MovieClip;
public function Main()
{
CreateEvents();
}
private function CreateEvents():void
{
boxSample = new MovieClip();
var graph:Graphics = boxSample.graphics;
graph.beginFill(0xff0000);
graph.drawRect(0, 0, 200, 200);
graph.endFill();
stage.addChild(boxSample);
var boxSampleEvent:EventHandler = new EventHandler(boxSample);
boxSampleEvent.addEventListener(MouseEvent.CLICK, OnClick);
boxSampleEvent.addEventListener(MouseEvent.MOUSE_DOWN, OnDown);
//to remove all events
//boxSampleEvent.RemoveEvents();
//to remove only one event
boxSampleEvent.RemoveEvent(MouseEvent.MOUSE_DOWN);
////////STAGE EVENTS///////////////////////////////////
var stageEventHandler:EventHandler = new EventHandler(stage);
stageEventHandler.addEventListener(MouseEvent.CLICK, OnStageClick);
stageEventHandler.addEventListener(MouseEvent.MOUSE_DOWN, OnStageMouseDown);
//to remove all events
//stageEventHandler.RemoveEvents();
//to remove only one event
stageEventHandler.RemoveEvent(MouseEvent.MOUSE_DOWN);
}
//BOX
private function OnDown(e:MouseEvent):void
{
trace("box mouse down");
}
private function OnClick(e:MouseEvent):void
{
trace("box mouse click");
}
//STAGE
private function OnStageMouseDown(e:MouseEvent):void
{
trace("stage mouse down");
}
private function OnStageClick(e:MouseEvent):void
{
trace("stage click");
}
}
}
That looks pretty good! That coupled with the Abstract class should handle all, if not most, of lingering events. Good Job!
@admin
Thank´s, your blog is very cool…always updated with some interesting stuff.
I´ve became a reader.
Hope to see some great posts about JigLib …
Thanks for this!
Don’t forget that events registered with ‘useCapture’ are treated as two separate handlers.
var oListener:Object = arrListeners[i];
this.removeEventListener(oListener.type, oListener.listener, true);
this.removeEventListener(oListener.type, oListener.listener, false);
should work fine.
I’m more of a destructor fan myself, and 90% you want to clear all listeners is because it’s about to be destroyed. Other than that, I remove listeners as soon as their no longer needed. I get what your saying though, a generic event listener remover.