Flex/Flash/Actionscript

Monkey Patching FlexSprite to list all event listeners on any Flex component

A while back Ben Clinkinbeard asked a question on flexcoders saying “Am I the only one who wishes EventDispatcher exposed its listeners?” The fundamental issue was that he wanted to get a list of all the event listeners that had been added to a given component.

The approach: using FlexSprite
Someone suggested monkey patching UIComponent to add this functionality, since each UIComponent gets notified each time a call to addEventListener is called, and you could keep track of the references locally. The thing is, monkey patching UIComponent is kind of a pain in the ass since it’s such a big class. When you monkey patch a class you basically need a complete copy of the whole class in your code so you don’t lose the functionality of that class. It’s perfectly doable with UIComponent, but gets kinda nasty.

So I was looking for an alternative and realized that the beautifully small FlexSprite class, which is the lowest level class you can get source code for (everything above it like Sprite, etc is built into the player). FlexSprite is under 100 lines of code and almost all of that is comments. When you get down to it there’s only a constructor and a single method in FlexSprite. So that makes it super duper easy to monkey patch the bastard. To refresh everyone’s memory the inheritance goes: Sprite -> FlexSprite -> UIComponent.

So if you’re trying to add in functionality that will trickle down into every component in the Flex framework, and you don’t need stuff specific to UIComponent, then the easiest way is to monkey patch FlexSprite.

The result
The good news: you can get a list of every event listener that is currently added to any component (at least anything that inherits from FlexSprite). This list will tell you the main details of the listeners, like type (ie “change”, “click”, etc), priority, useCapture, and useWeakReference. You also get the time when the listener was added (which is stored using getTimer to indicate the number of milliseconds since the app launched).

So now anything that inherits from FlexSprite (every display object in the Flex framework) has the following additional property and methods:

  • eventListeners – returns an Array of every event listener currently registered with the component. The Array contains ListenerTracker objects, which is a new class that simply holds the details of the listeners (like priority, etc).
  • removeEventListeners(type:String) – this will remove all event listeners for a given event type. You don’t have to have the reference to the actual listener function to remove it.
  • removeAllEventListeners() – removes all event listeners of all types. This completely wipes out all event listeners for the component all at once.

Here’s a very simple demo application that simply adds a button via MXML and shows all the event listeners on that button in a DataGrid. You can click the bottom button to remove all the listeners on the top button, which will effectively disable all interaction with the button, which should make sense.

This movie requires Flash Player 9.

Simple example | source

The bad news: so you get the function that was added as the listener, but you can’t get anything useful out of this, like the actual function name in the code. You also can’t get the name or reference of the object that contains the function, or that made the call to addEventListener. So that blows.

UPDATE: We can actually get the name of the class that called addEventListener(), the method name where it was called, and the exact line number. See my post about a sneaky trick to do this.

Basically you can see how many listeners of each type (and priority, etc) there are and you can remove any individual ones (or all of them at once). But we are not being able to get much information about a Function object itself. In the addEventListener function we get passed a Function, but you can’t get any more information about that object (see the listener column in the above example, it just shows the “function Function () {}” string, which doesn’t help at all). I’ve tried using describeType() on the Function and everything else I could think of but couldn’t figure out how to get any additional useful information about a function. If anyone has any ideas shoot me an email to let me know.

A cooler example
So I remembered seeing a pretty badass Flex library that let you explore all the properties and styles of any ui components in your application. I went back and found it, it’s called flexspy and is a project hosted on Google code created by Arnaud Pichery. So that’s cool, you drop the FlexSpy swc into your app and suddenly you get access to this cool real-time property and style inspector. (BTW, FlexSpy is licensed under the Do What the Fuck You Want To Public License, ha, awesome)

So I went and extended the FlexSpy component and added my own Event Listeners tab to the main inspectors. Now when you launch my version of FlexSpy you can see all the event listeners on whatever component you select. Dope. I added in buttons to let you remove any individual listeners, or all the listeners for any particular component. Here’s a screenshot, and the links to the example app and the source (view source is also enabled on the app).

screenshot0021.jpg

Enhanced FlexSpy demo | source

Standard