Saturnboy
 3.22

Managing Event Listeners in Flex 4

Event-driven programming is at the heart of Flex. It also lies close to the heart of insanity for the developer. When an application becomes too loosely coupled, things get painful fast. The perfect storm arrives when you marry an event-driven UI with an event-driven asynchronous backend. Better async testing becomes the least of your problems, and you are constantly trying to figure out who is listening to what, when.

In these cases, I often find that some simple runtime management of event listeners can really help. To begin, I start with some component whose listeners I want to manage, then I override the addEventListener() and removeEventListener() functions in that component to always keep track of who is actively listening.

Here is the basic code that can be added to any component (actually any descendent of EventDispatcher which is basically everything in Flex):

private var _listeners:Object = {};
 
override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void {
    super.addEventListener(type, listener, useCapture, priority, useWeakReference);
 
    if (_listeners.hasOwnProperty(type)) {
        (_listeners[type] as Array).push(listener);
    } else {
        _listeners[type] = [listener];
    }
}
 
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void {
    super.removeEventListener(type, listener, useCapture);
 
    if (_listeners.hasOwnProperty(type)) {
        var listeners:Array = _listeners[type] as Array;
        if (listeners.length <= 1) {
            delete _listeners[type];
        } else {
            var idx:int = listeners.indexOf(listener);
            if (idx != -1) {
                listeners.splice(idx,1);
            }
        }
    }
}

We just store all listeners of a given event type in an array, and store the array as the values in a hash keyed by event type. When a new listener is added via addEventListener(), we check if any listeners of that event type exist. If yes, we push the new listener onto the array. If no, we create a new one-item array containing just the new listener. The tracking process for removeEventListener() is just the opposite.

Once we have all the listener bookkeeping in place, we can add any type of event listener management that we want. For example, he’s a removeAllEventListeners() function:

public function removeAllEventListeners(type:String = ''):void {
    if (type.length == 0) {
        for (var t:String in _listeners) {
            removeAllEventListeners(t);
        }
    } else if (_listeners.hasOwnProperty(type)) {
        if (hasEventListener(type)) {
            for each (var listener:Function in _listeners[type]) {
                removeEventListener(type, listener);
            }
        }
    }
}

Nothing cosmic, as my boss likes to say, just walk all the listeners of a given event type and remove them. If the event type is blank, just use some dirty recursion to walk all the types to remove everything.

Here is a sample application which is tracking all the listeners on a Panel component (view source enabled):

Flash is required. Get it here!

You can add/remove a custom listener for the foo custom event type using the buttons. Or hit remove all to clear everything (including the listeners attached by default by the Flex framework).

Files

Comments are closed

© 2017 saturnboy.com