Building a Static EventDispatcher in AS3

One of my favorite features of AS3 is the low-level inclusion of EventDispatcher in the AS3 framework. I do not miss the days of including EventDispatcher mix-ins in 80% of my classes in 100% of my projects. I especially like the additional features of the AS3 EventDispatcher: cancellation, custom event types (built in), preventDefault, event phases, etc.

However we have had several AS3 projects that have had a need for an EventDispatcher that is not instance-based. So, without further ado, here is an approach that we have used since our AS2 days:

package {
import flash.events.EventDispatcher;
public class MyClass {
protected static var disp:EventDispatcher;
public static function addEventListener(...p_args:Array):void {
if (disp == null) { disp = new EventDispatcher(); }
disp.addEventListener.apply(null, p_args);
}
public static function removeEventListener(...p_args:Array):void {
if (disp == null) { return; }
disp.removeEventListener.apply(null, p_args);
}
public static function dispatchEvent(...p_args:Array):void {
if (disp == null) { return; }
disp.dispatchEvent.apply(null, p_args);
}
// Other class code
}
}

Note that this differs from a Singleton approach, in that I didn’t want to force a user to extend EventDispatcher (plus I dislike getInstance()). Additionally, some of my fellow developers have noted that using the apply syntax instead of defining all the arguments with types is lazy. Since this runs through an actual EventDispatcher instance, and this class is just a proxy, I didn’t think they were necessary.

I hope someone out there finds this useful. Internally we use it quite often – and it seems to be the most reliable way to add static-access events to a class.


Update
Since I was scolded for not typing the arguments, here is an update, and a sample usage.

package {
import flash.events.EventDispatcher;
import flash.events.Event;
public class MyClass {
protected static var disp:EventDispatcher;
public static function addEventListener(p_type:String, p_listener:Function, p_useCapture:Boolean=false, p_priority:int=0, p_useWeakReference:Boolean=false):void {
if (disp == null) { disp = new EventDispatcher(); }
disp.addEventListener(p_type, p_listener, p_useCapture, p_priority, p_useWeakReference);
}
public static function removeEventListener(p_type:String, p_listener:Function, p_useCapture:Boolean=false):void {
if (disp == null) { return; }
disp.removeEventListener(p_type, p_listener, p_useCapture);
}
public static function dispatchEvent(p_event:Event):void {
if (disp == null) { return; }
disp.dispatchEvent(p_event);
}
// Public API that dispatches an event
public static function loadSomeData():void {
dispatchEvent(new Event(Event.COMPLETE));
}
}
}
MyClass.addEventListener(Event.COMPLETE, onComplete, false, 0, true);
function onComplete(p_event:Event):void {
trace("Complete!");
}
MyClass.loadSomeData();

Lanny McNie

As the dev mgr, Lanny oversees the technical day-to-day details of production and makes sure things get out the door.

@astrostyle

37 Comments

  1. I agree, apply is lazy. The params should be typed for compile time error catching (bad Lanny).

    Also, it should be noted that with this approach that the event target will be pointing at the EventDispatcher instance, not the class.

  2. This is very good!

    Could you post an example of how to use it?

  3. I am lazy too. My composed EventDispatcher examples also use apply πŸ˜€

  4. can you explain when you need an event dispatcher that is not instance-based? i’m new to this and don’t quite understand the use case scenario.

    thanks.

  5. I like doing the same thing, though I ended up just using a package constant.

    package onyx.constants {

    public const SOME_DISPATCHER:EventDispatcher = new EventDispatcher();

    }

  6. I agree with your decision to use composition rather than inheritance for the EventDispatcher, however I am curious why you don’t like ‘getInstance’. I realize not everyone is a fan of the Singleton pattern, but I was just wondering what your reasoning was.

  7. For me the getInstance() static method is a better solution πŸ™‚

    In your getInstance() method you can add a “channel” parameter and creates global dispatchers… After you can use the EventDispatcher.getInstance( channel ) method to creates and use global references with a FrontController pattern πŸ™‚

    Example with my opensource framework VEGAS and this AS2 version :

    http://code.google.com/p/vegas/wiki/VegasTutorialsEvents_multi

    http://code.google.com/p/vegas/wiki/VegasTutorialsEvents_frontcontroller

    After when the static getInstance is implemented … i prefere use an Abstract class to creates my other local/global dispatchers… My dispatcher can change dynamicly the event flow with a method setGlobal( flag:Boolean , channel:Boolean )

    http://code.google.com/p/vegas/wiki/VegasTutorialsEvents_AbstractCoreEventDispatcher

    For the moment the AS3 version of my framework is in progress but for me this implementation is really important !

    EKA+ πŸ™‚

  8. For me the getInstance() static method is a better solution πŸ™‚

    In your getInstance() method you can add a “channel” parameter and creates global dispatchers… After you can use the EventDispatcher.getInstance( channel ) method to creates and use global references with a FrontController pattern πŸ™‚

    Example with my opensource framework and this AS2 version :

    http://code.google.com/p/vegas/wiki/VegasTutorialsEvents_multi

    http://code.google.com/p/vegas/wiki/VegasTutorialsEvents_frontcontroller

    After when the static getInstance is implemented … i prefere use an Abstract class to creates my other local/global dispatchers… My dispatcher can change dynamicly the event flow with a method setGlobal( flag:Boolean , channel:Boolean )

    http://code.google.com/p/vegas/wiki/VegasTutorialsEvents_AbstractCoreEventDispatcher

    For the moment the AS3 version of my framework is in progress but for me this implementation is really important !

    EKA+ πŸ™‚

  9. I haven’t seen an example of where I’d need static event dispatching. The idea of EventDispatcher is that you are listening for events that occur on an object. In your code, the event target will be some useless object that has no meaning to any other object in your application.

    Can you explain a use-case?

  10. This mediator style approach I think is much nicer than using a generic dispatcher ( which is extensible but not as discoverable ) and also nicer than bucket-brigade bubbling ( which is discoverable but not as extensible ) – I’ve been doing this same thing in my AS3 projects, so it’s nice to know I’m not alone in the approach.

    I also dislike the getInstance approach ( not sure why ), but I’ve been using it with an inheritence instead of composition for this class, with the specific calls ( like loadSomeData ) still being statics. Thoughts on the different approaches, pros / cons?

  11. Here’s an example of how I approached it :

    
    package  {
    
    import events.*;
    
    import flash.events.EventDispatcher;
    
    import flash.utils.getQualifiedClassName;
    
    public class ApplicationMediator extends EventDispatcher {
    
    public static const DO_STUFF:String = "app-event-do-stuff";
    
    public static var _instance:ApplicationMediator;
    
    public function ApplicationMediator() {
    
    if ( getQualifiedClassName( super ) == "::ApplicationMediator" ) {
    
    throw new ArgumentError( "Use get instance pl0x." );
    
    }
    
    }
    
    public static function getInstance():ApplicationMediator {
    
    if ( _instance != null ) { return _instance; }
    
    _instance = new ApplicationMediator();
    
    return _instance;
    
    }
    
    public static function doSomeStuff( e:DoStuffEvent ):void {
    
    _instance.dispatchEvent( e );
    
    }
    
    }
    
    }
    
    

  12. I LIKE!

    Why not edit the Static Event Dispatcher’s event call, so that you can pass custom events like-a-dis:

    // Public API that dispatches an event

    public static function customEvent(e:String):void

    {

    dispatchEvent(new Event(e));

    }

    //now you can add const properties for an object, and dispatch them like-a-dis:

    public static const OBJECT_CLICK:String = “OBJECT_CLICK”;

    DispatchClass.customEvent(TheObject.OBJECT_CLICK);

    Now some other object in a whole can listen for this event, without ever knowing the target object ever existed, well without a passed reference at least!

    DispatchClass.addEventListener(TheObject.OBJECT_CLICK, objectClickHandler);

    booya kasha! That’s what I was looking for!

    Thanks Grant, the static event Dispatcher saved me much time!

  13. dang, sorry for all the typos/broken sentences, I’m in a hurry my fried!….ahem, friend!

  14. Thanks Lee, that’s almost exactly what I need but how could you send object parameters to the listeners?

  15. Thanks Lee, That’s almost exactly what I need. But how could you send an object with propertis to the listeners?

  16. What’s so great about a global dispatcher?

    Global dispatchers always feel like a cop-out to me…I was even hesitant towards adopting the one used in cairngorm.

    Objects should always have control over what subjects it is listening to. This becomes increasingly important as projects become larger and naming conflicts of event types become more likely.

  17. I agree with (and we use a ton of) event ‘channel’ instances in our applications, aka the style demonstrated in Vegas.

    Since almost everything under AS3’s core framework is inheriting from EventDispatcher it is a given that when you need to listen for discreet Events from specific objects (display or otherwise) the wiring is pretty much all there for you to just jump on, and the new additions are really nice.

    But if you want to come up with ways to manage or organize all those interconnections of Events the ‘channels’ approach can be a very useful tactic. If you think of a channel essentially as an intermediary between event sources and their handlers (effectively decoupling the two) which also provides a means to mediate events, you can see there are quite a number of handy strategies you can apply it to.

    One advantage is you don’t have to worry so much about adding and removing listeners every time you create or destroy objects. If you have a ‘cart’ where items can be added/removed, whatever controls adding/removing items to that cart’s model doesn’t have to be explicitly wired to listen to every single object that could end up adding/removing an item, it just has to listen to the ‘item events’ channel which individual controls/views in turn dispatch their item add/remove events through. In turn the channel itself can be employed to filter, mediate or queue events (for example if for a period the cart could not be used because it was processing a transaction), or can be used as the place to keep a stack of events that act as a history. Event sources only need to worry about generating events, not managing who listens to them, and event destinations only need to worry about subscribing/unsubscribing from a given ‘category’ of events as needed. The real target or origin of the Event itself can be passed as a reference in the Event in cases where the channel would occlude access needed back to the Event’s ‘true source’.

    All said it is just one possible architecture. I’m thinking I probably like it because I come from a background involving music production, and I always thought of event connections and communications between objects being similar to patch cable connections… and it is always nice to be able to route patch cables through patch bays or buses to manage the wiring.

    One issue we’ve had with the built in framework EventDispatcher (IEventDispatcher) is you don’t have a way to access the listeners collection itself. Processing the listeners collection, albeit dangerous if mishandled, allows you to do a lot of useful things (remove all listeners easily, remove all listeners for a specific event type, remove all listeners to a specific handler, filter on certain conditions, mediate listeners on/off, re-wire listeners to other sources, etc.). To get around this we wrote our own extended event dispatcher which basically keeps a local stack of listeners, but unfortunately it is awkward to propagate that into the subclasses of the normal EventDispatcher (like Sprite(), etc.).

  18. There are places where a global dispatcher is appropriate, however if the nature of the class is a “global dispatcher” instead of something more specific, then you’ve probably made a mistake in your design. In other words if you have a high level class that has responsibilities including routing messages between lower level classes, and that class implements/uses a global dispatcher that’s fine. If you have a class that is only a dispatcher, then it’s going to be too vaguely designed to be useful.

  19. Just came accrosss this post and this class reminds me one I’ve done some times ago ( 2 years ago for as2 ).

    http://dev.webbymx.net/2006/07/13/as2-listening-the-event-of-a-class/

    Back then I had feedbacks, most of them were like “why listening to a class”, you nuts???

    Glad to see that I’m not the only one πŸ™‚

  20. Very handy indeed. Thanks

  21. Another method would be to use the static staticEventDispatcher instance that the Flex compiler adds classes with one or more static variables ?

    http://thecomcor.blogspot.com/2008/07/adobe-flex-undocumented-buildin.html

  22. One case where the Instance() is a problem is with the ProgressEvent, since this event happens repeatedly until the progress is finished.

  23. I’m a little new at AS3, and I am trying to use your StaticEventDispatcher (the class I built with your code) for all static classes I’ve built. When I try to extend the class and add and event listener to my class, it tells me that I’m accessing and undefined method. Shouldn’t the extension allow my class to inherit the methods of yours?

  24. @David

    When you extend a class, you do not inherit the static methods, only the instance methods. You will have to add the static event dispatching methods to each class that you want to use it.

  25. Ah, I understand that now. The real problem is that I did not have my brain fully wrapped around the concept if this. Now, I get it!

    This an awesome way to program! I built something similar in AS2 once I got the concept, and it made programming so much easier. None of the objects have to be aware of each other any more, which I think is the purpose of a true MVC environment.

    I do agree that without using “channels”, event naming can get confusing. However, if you are working in a group of other programmers, enforcing custom Events can also sole that problem, as long as the Event values are unique. For instance, you wouldn’t make the values for MyButtonEvent.CLICK and YourButtonEvent.CLICK to be “CLICK”. Otherwise, the listeners won’t know the difference. I prefer to make the string value the name of the Class, underscore, then the name of the Event (“mybuttonevent_click”);

    In this case, which do you think is preferable? The above method, or the “channel” method?

  26. Amazing!

    Just what I was looking for πŸ˜‰

    Thanks!

  27. Thanks Grant – this is exactly what I needed.

  28. PERFECT!!!!

    Thank you so much!

    I’ve been trying to dispatch events from a singleton, and this was exactly what I needed.

  29. This is a huge help for me as a developer still getting used to the nuances of AS3 and its abilities/restrictions. It works just fine!

  30. Useful post.. thanks a lot.

  31. I’ve talked to a couple of other developers about using a StaticEventDispatcher, and they said that memory leaks are a common problem in larger projects. Have anyone else run into this issue, and if so, have you discovered a way around it? Someone mentioned making it possible to “cancel” custom events, but I’ve not been able to see how or even test it. Thanks!

  32. This helped me so much. I have been using a static class workaround for a year that confuses other developers. Great article and I appreciate the updated example.

    Interested in hearing back from David’s post about canceling custom events.

  33. Hi There! Absolutely loved this example, it’s so simple and straight to the point. Got a question though…

    “However we have had several AS3 projects that have had a need for an EventDispatcher that is not instance-based”

    What would a version of this one look like if it were instance based?? (I know, there are plenty of examples out there, but I’m still trying to wrap my head around events and a side by side comparasion of these 2 eventdispatchers would help me a great deal…)

    Thx,

    Rob

  34. This is all i need thanks alot!

  35. Great point Grant! I had the same problems with native Event API of Flash.

    Talking about static “EventDispatcher”, here a new Flash Event Egine that work together with static and instantiated mode.

    Great to all kind of events in an application.

    http://code.google.com/p/nineveh-responder/

    or the blog page

    http://db-in.com/blog/nineveh-framework/nresponder

    Bye.

  36. Thanks a lot !

    very useful !

  37. Skinner’s use of apply() is actaully pretty appropriate because if in the remote chance the ActionScript API changes the parameters, the library is compatible across versions…. Jus’ sayin’. I did a version that did use getInstance() though…

Leave a Reply

Your email address will not be published. Required fields are marked *