August 2004


Ever since Flash MX 2004 Pro was released, I’ve been struggling with the question of how to create a lightweight preloader for movies that use v2 components. The basic problem is that the v2 components come with a large ActionScript class library that can add a substantial amount to even small movies that use even one component.

For awhile I’d been using an approach that involved a small preloader movie that displayed a loading animation and progress bar, and used loadMovie() to load the content movie (with components) into an empty clip. This worked in many cases, but it turns out that there are some v2 components, such as ComboBox and Window, that don’t work properly when they’re loaded into a sub-clip in this manner. Basically, those components contain code that makes explicit references to the _root timeline, which is a no-no. The Macromedia docs suggest using the _lockroot property on the target clip in order to trick the components into seeing the proper timeline as _root, but in my experiments I have found that this does not always work.

Recently, thanks to an entry in Jesse Warden’s blog, have been able to create a preloader that works with movies that use v2 components. As an added bonus, the preloader does not need to reside in a separate swf file, and thus doesn’t need to mess with _lockroot — it can be implemented as part of the main movie. I’ll describe the steps needed to accomplish this below, if for no other purpose than to remind myself of what I did!

Start with a movie that uses v2 components. Open up the library and identify these two types of symbols:

  1. all component symbols (Button, ComboBox, Label, Window, etc.)
  2. all compiled clips and/or movie clips that will be dynamically instantiated at runtime; this includes View symbols for window and accordion contents, component skin symbols, etc.

I usually keep these types of symbols in a separate folder in the library. For each of these symbols, right click and open the “Linkage…” dialog, and deselect “Export in first frame”. This prevents the code and assets for those symbols from being loaded at the very beginning of the movie, which means we’ll be able to put up a preloader before those start loading. It’s very imporant to indentify all components and dynamically instantiated symbols used in the movie and edit their library symbol entries in this way.

One important exception to this is the DataBindingClasses symbol that gets added to the library automatically whenever you use a v2 component in a movie. This symbol needs to have “Export in first frame” checked. I think the reason for this is that it needs to load before any components do. At any rate, even though we’re leaving it as one of the things that gets loaded at the very beginning of the movie, it’s not very large so it shouldn’t affect the preloader loading time too much.

The next step is to add three blank keyframes to the very beginning of the main timeline. There should initially be nothing at all on the stage on these frames; in other words, all your main movie content needs to be shifted three frames to the right. At this point I also usually add a new movie layer called “preloader”, and I’m also assuming that you already have a “script” or “code” layer that contains only frame actions.

The first two of the three new frames will be used for the preloader loop. Frame 1 actions should look like this:

// Frame 1 actions
trace(getBytesLoaded()+" of "+getBytesTotal());
if (getBytesLoaded() > 0 && getBytesLoaded() >= getBytesTotal()) gotoAndPlay(3);

Of course the trace is optional, and could be replaced with a line that sets the percentage loaded value on a progress bar or other indicator. Next, set this line as the frame 2 action:

// Frame 2 actions
gotoAndPlay(1);

These two frame actions are just the typical way to “pause” a movie until the whole swf file has loaded on the client machine. Once the entire movie has loaded, the playhead is allowed to proceed to frame 3. Your lightweight preloader animation and/or loading indicator can be put on the stage on the “preloader” layer spanning frames 1 and 2, so that they are visible during the preloading process.

The next step is to create a special frame on frame 3, which contains instances of all the symbols for which we unchecked “Export in first frame” in the first step (this is why we organized them into a special library folder earlier). Create a blank keyframe at frame 3 on the preloader layer and drag one instance of each such component onto the stage but outside the movie’s viewable area. What we’re doing here is telling the Flash compiler that it will indeed need to load these assets for use on frame 3 and beyond (since it’s not going to load them at the beginning of the movie as usual). These component instances don’t have to stay on the stage past frame 3; a brief appearance on this single frame is enough to tell the compiler when they need to be loaded.

The observant reader will note that it’s not actually necessary for each and every one of these clips to be instantiated on frame 3, since many of them probably appear on the timeline later on past frame 3 anyway. Technically this is true — all we really need is for each symbol that gets dynamically instantiated by application ActionScript code, and therefore isn’t statically placed on the timeline in the authoring environment — to be instantiated in this way on frame 3. This includes some components, namely Window, which tends to be instantiated at runtime using the PopupManager class. However, it doesn’t hurt just to instantiate everything on frame 3, so I’m recommending that as a less error-prone approach.

The final — and quite critical — step is to tell the compiler that ActionScript classes should be loaded on frame 3 instead of frame 1. This can be done by going to the dialog at File Publish Settings… Flash (ActionScript) Settings… and setting the “Export Frame for Classes” value to 3. This prevents the huge chunk of ActionScript class code that comes along with the v2 components from being loaded at the beginning of the movie and thus trumping the preloader. The important thing is that the class export frame be no later than the frame on which the symbols that use those classes first appear.

At this point your timeline should look something like this:

Timeline

In the above image, the frame colors correspond to:

  • orange: the two script frames with the preloader loop actions described above
  • green: any lightweight preloader animation and/or loading indicator clips
  • yellow: the special frame on which any dynamically instantiated symbols are manually instantiated on the stage but outside the viewable area
  • blue: the main movie that is being preloaded

You should be able to verify that the loading sequence is working as intended by selecting “generate size report” on the Flash Publish Settings dialog, and examining the report to ensure that the bulk of the movie doesn’t get loaded until frame 3.

Some design patterns require the use of a static initializer, a block of code that should execute once and only once the first time a class is referred to. The typical use for this pattern in ActionScript programming is when a mix-in class needs to be used, as in the case of the mx.events.EventDispatcher class. EventDispatcher contains a static method, EventDispatcher.initialize(), which can be invoked to add the event framework methods to any arbitrary class.

Say we have a class called ActionManager that needs the event handling mix-in methods. One approach would be to invoke EventDispatcher.initialize(this) in ActionManager’s constructor method; however, this approach suffers from the drawback that the EventDispatcher initializer could be invoked multiple times (each time a new ActionManger instance is created), when it really only should be invoked once.

If we were programming in Java, we’d be able to do something like this, using the static initializer syntax:

public class ActionManager {
static {
mx.events.EventDispatcher.initialize(ActionManager.class);
}
public ActionManager() {
...
}
...
}

Now, ActionScript doesn’t have this sort of static block syntax, but fortunately there is a way to accomplish the same thing:

class ActionManager {
private var staticInitialized:Boolean = staticInitializer();
private static function staticInitializer(Void):Boolean {
mx.events.EventDispatcher.initialize(ActionManager.prototype);
return true;
}
public function ActionManager(Void) {
...
}
}

The ActionScript pattern illustrated above does the same thing as Java’s static initializer block syntax — the staticInitializer() method will only be called once, the first time the class is referenced, and before the constructor method is invoked.

Although this pattern is typically used to set up mix-in classes such as EventDispatcher, it is also useful for setting up arbitrary static class memebers such as lookup tables, etc., which only need to be calculated once across all instances of a class.