A few weeks ago, I worked on a project based on the Youtube AS3 API and I was really surprised how Flash developers still have concerns with event management.
When I started the migration from SPAS 2.0 to SPAS 3.0, in 2006, one of the first classes I created was the
EventCollector class. This class has been especially designed to solve these problems. So I have decided to share it within an autonomous package, even if it is still a core part of the SPAS 3.0 API. That means the
EventCollector class is now compatible with Flash, Flex (Flash Builder and Flex SDK) and all of the available ActionScript 3.0 APIs and projects on the Web.
In order to go through this tutorial, we assume that you have an ActionScript 3.0 environment set-up and that you are familiar with the basic concepts of event handling.
The event DOM-based model, introduced with ActionScript 3.0, was a fantastic improvement for building complex applications. (Maybe some of you guys remember the good old Delegate class.) But if we pay attention to the memory leaks issues in ActionScript, arguably the persistence of object references through events is responsible in most of the cases. Because the event model is very flexible and easy-to-use, event listeners are often disseminated all over the code, without any rules or well defined structures. The fact is that if you implement a large number of unorganized lines of code within an application, you introduce "chaos in the computer"!
Now, just imagine a complete on line music editor, with tens of modules called, created, and displayed on the fly. Each module is composed of many different classes which are responsible for synchronous or asynchronous treatments (loading and saving data, playing back music, checking for music theory rules, etc.). Such an application cannot be developed if you do not take care of memory usage. Unfortunately, there is no way to easily fix event management issues. Each event listener must be removed before deleting unused modules and this could become really fastidious when you have to check hundreds of classes.
As we commonly say: "The simplest ideas work the best."
And the event collection concept is probably one of the most simple reusable piece of code ever written in ActionScript.
We know, that (fortunately) there are no mechanisms to automatically remove event listener references when setting an object to null. But if we consider the process of deleting an object, we would never have to know the number or type of event listeners associated to it and what they are doing. Our only concern should be to ensure their destruction.
That is precisely what the
EventCollector class does! So, it has been designed with two main goals:
EventCollector class has been the SPAS 3.0 core event manager since 2006, which means that its robustness, efficiency and flexibility have been well-tested for many years.
Before exploring the class API, remember that
EventCollector instances must be accessed from any part of your object, but always hidden from the public API. (See Chapter 8 for exceptions.)
Most of the time, we will only use two methods for managing events:
All parameters of the
addEvent() method are the same as the parameters of the
addEventListener() method, defined by the
IEventDispatcher interface, except the first one, which is the listener object itself.
Note that the
funcparameters of the
addEvent()method represent respectively the
listenerparameters of the
The common use of the
EventCollector class is shown below:
The following code does the same without using an
To remove the registered event handler, you call the
removeEvent() method with only three parameters: the listener object, the event type and the associated function. The code below shows how to remove the event handler we added above:
This is the minimal API you need to know to work with the
The event collection process provides many more methods to implement mechanisms based on the
IEventDispatcher interface (e.g.
hasRegisteredEvent()), or custom convenient methods (e.g.
addEventCollection()). For more information about methods of the
EventCollector class, go to the SPAS 3.0 documentation at: http://www.flashapi.org/spas-doc/
In the previous section we saw that the
EventCollector class behaves exactly as objects that implement the
IEventDispatcher interface do. At this point, it does not solve the problem raised earlier. For example, let's imagine an object which is responsible for creating and deleting a random range of particle objects. The following sample class illustrates such an object:
In this example, the
createObj() method creates a random number of sprite objects and adds them to the display list of the
_sprite instance. Then, the
deleteObj() method sets the
_sprite instance to
If you do not associate some event listeners to its children, setting the _sprite instance to null will make all the contained sprite objects eligible for garbage collection. But as we have added an event listener to each child, all of them remain in memory.
This class reproduces a common coding case often encountered across the Flash community.
The best way to prevent the issue described in this example is to use the
removeAllEvents() method provided by the
EventCollector class. As we said in the previous chapter, welldesigned applications imply that we do not need to know anything about the registered events; we just have to remove all of them. When calling the
removeAllEvents() method, all events listeners registered through the
EventCollector instance are automatically deleted for all added objects.
Replace the preceding
deleteObj() method by the following one and launch the Flash Builder, or FlashDevelop, "objects profiler" to compare the result in both cases:
This is probably the most simple and convenient mechanism to prevent memory leaks due to event management.
As you can see, the
EventCollector class respects the assumptions set out in Chapter 4: gaining time and ensure deleting event references in all cases.
The sample class in Chapter 6 is probably too short and too basic to illustrate the real benefits of using the
EventCollector class for managing all of your events within a Flash application.
In Chapter 3, we talked about managing "hundreds of classes". And inevitably, this leads us to think about how we design our applications on the Flash Platform. Remember what we said above: "The simplest ideas work the best." Bertrand Meyer introduced Modular OOP about 15 years ago [MEYER, 1997]. As everything has already been theorized, we just have to apply some of these concepts to make better software.
By combining modular design (consider classes as modules) and a few simple techniques, such as the
EventCollector class, it should be possible to definitely close discussions about memory leaks on the Flash Platform. A base rule should be accepted by everyone:
Each time a main object is responsible for creating a strong reference in the memory to any other object, it should provide a visible mechanism for removing this reference.
This is a global concept, so "visible" means "accessible by the consumers of the main object".
For example, SPAS 3.0 API implements such a process through the
finalize() methods. According to this, if we consider the sample class from Chapter 6, the
deleteObj() method should be rewritten as shown below:
For a more global transcription, regarding ActionScript 3.0 practices, the original rule could be simplified to this one:
Each time a class instance is responsible for creating a
BitmapDatainstance or an event listener, it should provide a public method for deleting the reference of this object.
Moreover, the logical name of such an action should be "destroy". And that is where the
EventCollector class is really interesting to use, because we no longer need to pay attention to the event listener references we have created to delete them later. A single command is used to carry out this task:
By applying this code snippet to all of your developments, you could create much better reusable libraries, components or applications.
When you are designing an object-oriented application, it is not advisable to share functionalities across several different modules. The direct consequence is that sharing an
EventCollector instance, between two or more classes, is not good practice.
However, it is always possible to implement a shared
EventCollector instance in the MVC pattern. But to be efficient, you must follow some basic rules to design the structure of the pattern:
EventCollectorinstance must be a singleton.
EventCollectorsingleton must not be used by an object which does not belong to this module. (Principle of Retention of Information.)
removeAllEvents()method must be the first action called within the destroying method implemented by the model. So, the structure of events management inside each object must be designed to respect this rule. (This is based on the principle of Modular Composability.)
Even if it is technically possible to do that, it seems wise to discourage the use of such practices! Unfortunately, the MVC pattern is not the best way to simplify the management of memory leaks. Thus, whatever the considered solution, it will not be easy to implement it.
In any case, you should implement a destroying method each time the rules introduced in Chapter 7 are confirmed.
In this article, we learned how to use the
EventCollector to simplify and improve the management of event handling in ActionScript 3.0. By now, you should be able to implement the
EventCollector API in your existing and new projects by using the concepts explained in Chapter 7.
To be informed of new releases, latest information and documents about the collector API, or support SPAS 3.0 projects, follow us on the SPAS 3.0 Facebook page at: http://www.facebook.com/flashapi
We need your feedback to add functionalities to the collector API, so feel free to post your comments on the page devoted to this article, on the SPAS website at: ActionScript 3.0 Best Practices: Using the EventCollector Class
[MEYER, 1997] Bertrand MEYER, Object-Oriented Software Construction, second edition, Prentice Hall, 1296 pages, January 1997.