One of the major limitations of setting up large dynamic applications in Flash MX 2004 is that most of your content (and hence most of your file size) gets dumped onto frame 1. This is especially true if you use a lot of Macromedia components.

There are a number of workarounds for this, including setting up an external file to handle pre-loading, but the best one I have found is to carefully move all of the content off of the first few frames, so that you can set up a proper preloader within the swf in the first two frames.

There are a number of steps to achieving this - I will walk through each of them, and you can download a simple demo at the end of this entry.

1) Set your publish settings to export AS2 classes export on a frame other than 1
By default, Flash compiles all of your AS2 classes onto the first frame of your SWF, so that they are ready to be used immediately when your SWF loads. Of course, this adds a lot of bulk to the first frame of your application. Luckily, we can override this behaviour.

In this example I'm going to set my classes to export on frame 5, so that I can set up a preloader in the first few frames. To accomplish this, simply open Publish Settings from the File menu, click on the Flash tab, then on the ActionScript 2.0 "Settings..." button. In the dialog that opens, type "5" into the "Export frame for classes" box.

2) Set up exported library items to load on a frame other than 1
As with classes, Flash defaults to exporting all library items that are set to "Export for ActionScript" to export on frame 1. In order to circumvent this, you must go through your entire library and find each item that is set to export for ActionScript. Then, for each of these items you must turn off "Export in first frame" and add an instance of the symbol to the frame you have decided to export your assets on (in this example, frame 5).

This is a very laborious process in larger projects, and for ongoing projects it can be very difficult to remember which symbols are set up properly for preloading, and which still need to be set up. To solve this problem, I developed a simple JSFL script which automates the entire process: It identifies symbols that haven't been set up, turns off their "Export on first frame" property, and adds an instance of the symbols to whatever keyframe you specify. And because it only affects symbols that are not already set up, you don't have to manage the process. One of our current projects has over 800 symbols in the main FLA, almost 200 of which are exported for ActionScript - as you can probably imagine, this JSFL has saved me a LOT of time.

You can download the JSFL, and find instructions for using it at the end of this entry.

3) Set up the preloader
Now all of your assets are loading on frame 5, so you have 4 frames to play with for preloading - this example only uses a single frame, but the timeline is easier to work with when it's a little spaced out. The most important thing to remember is to not use embedded fonts, classes, or components in your preloader, otherwise you're defeating the purpose.

For this example, I'm just going to set up a super simple preloader that just puts the percentage complete into a textfield (using _sans system font) on the stage. I could use the same percentage value to drive a progress bar or something fancier, but I want to make it easy. Here's the code, placed on frame 2, together with a textfield called "loadStatus" - I use frame 2 so that Flash even has an opportunity to properly preload that frame before the playhead hits it:

onEnterFrame = function() {
   var percentLoaded:Number = // wraps to next line:
       Math.floor(getBytesLoaded()/getBytesTotal()*100);
   if (percentLoaded == 100) {
      // clean up:
      delete(onEnterFrame);
      // jump over our asset frame, and
      // straight to our content frame:
      gotoAndPlay(10);
    } else {
      loadStatus.text = "Loading: "+percentLoaded+"% done";
    }
}
stop();
As you can see in the above code, once I hit 100% loaded, I skip over the frame I exported all of my assets to (otherwise I would get a really ugly screen with them all scattered everywhere - not to mention the CPU hit of instantiating them all at once), and straight to my frame with my application content. Also, don't forget to delete your onEnterFrame function - you don't want it to keep running in the background eating up resources.

The "Set up for preloading command"
As I mentioned above, I've scripted a simple, but very useful JSFL command that will automate prepping your symbols for preloading. To use it, follow these simple steps:

  1. download it by clicking here
  2. open it in Flash (using open... in the File menu, not by double-clicking it), and read the little disclaimer at the top
  3. open your FLA, and select the keyframe you want all of the symbols that are set to "Export for ActionScript" to be exported to
  4. Select "Run command..." from the command menu, and select the JSFL file
The command will search your library for any symbols that are set to export in the first frame. For each of these symbols, it will turn off "Export in first frame", and create a new instance on the stage in the keyframe you selected. Simple!

NOTE: JSFL files have the potential to break things in your work - I would urge you to run them on copies of your files, rather than your originals in case something goes wrong.

You can download the demo mentioned in this entry by clicking here. Take a look at the bandwidth profiler when you test movie to see where the assets are being loaded.

[UPDATE JULY 16/2005]
There have been several comments on preloading audio clips. The approach we took was to create a single movie clip, and put each audio clip on a layer/frame. Note that audio will sometimes still play, despite being in a frame that's never hit, so all the audio frames are changed to "stop" events.

You can download an updated jsfl here