ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Preloading in ActionScript 3.0, the Easy Way
http://www.actionscript.org/resources/articles/869/1/Preloading-in-ActionScript-30-the--Easy-Way/Page1.html
Christopher Skyi
Brooklyn Sky DesignBrooklyn Sky Design was created in early 2007 to address the needs of artists, individuals, and small & medium size business who are seeking an affordable web presence on the internet. We provide internet programming and web site design and build services.

Brooklyn Sky Design has several years experience in both application web programming (e.g., http://ASP.Net, Flash-Actionscript) and web site design and building. Brooklyn Sky Design recognizes the importance of solid design principles based known usability principles. In other words, we make sure your site not only looks great but that it also works and functions from a user's point of view.

 
By Christopher Skyi
Published on February 19, 2009
 

Difficulty: Easy
Time Needed To Work Through This Tutorial: 40 - 50 minutes.

Introduction: With ActionScript 2.0, the details about how to build a good preloader evolved over time to a point where it became relatively easy and painless to add a preloader to your application that worked in just about all the browsers.

Boy, did all of that change with the introduction of ActionScript 3.0.

If you want to take the basic ActionScript 2.0 approach and re-work it for ActionScript 3.0, you can do that -- but it's a lot of work.

If, however, you’re looking for something easy, fast, and reliable, you’ve come to the right place.


ActionScript 3.0 Preloader: Clean, Easy, & Reliable
A lot has changed from ActionScript 2.0 to ActionScript 3.0, mostly for the best (but check out Colin Moock’s The Charges Against ActionScript 3.0, “O’Reilly InsideRIA Blog,” July 15, 2008.  With ActionScript 2.0, the details about how to build a good preloader evolved over time to a point where it became relatively easy and painless to add a preloader to your application that worked in just about all the browsers.

Boy, did all of that change with the introduction of ActionScript 3.0 -- at least if you were using custom classes and components in your flash applications, as most non-trivial flash applications do.

Now it is possible to take the basic ActionScript 2.0 approach and re-work it for ActionScript 3.0 -- in fact, Jamie Kosoy, Senior Developer at Big Spaceship, has written an excellent tutorial, ActionScript 3.0 for developers and designers – Part 1: Creating a preloader, but the techniques are involved. Still, you should make the time to work through Jamie’s tutorial, as you’ll learn a lot about the ActionScript 3.0 architecture and modular programming.

However -- if you’re looking for something easy, fast, and reliable, you’ve come to the right place.

This tutorial is based on the excellent preloading tutorial by Lee Brimelow at Adobe. You can actually watch him build this simple preloader on the gotoandlearn.com site. However, there’s no accompanying write-up, which is where this tutorial comes in.

I’ve broken this tutorial up into two sections.  If you just want the basics, and the code, without a lot of involved discussion, then just read Part I. In Part 2 I use the same code, but I show how this new preloading technique rests on the new Display API of ActionScript 3.0.

Ready?  Here we go!


Part 1. “Dude, just gimme the preloader!”
The idea is to have a simple SWF file that loads another SWF file. That’s its only job. This is a huge simplification because you don’t have to deal with exporting resources on different frames, the issues that surround the document class references, etc. 

(Quick Aside: while you could also use a SWF file to load another SWF file in ActionScript 2.0, you had to be very careful about how you used the “_root” variable. This is because, in ActionScript 2.0, “_root” referenced the main timeline of the original SWF file no matter how many SWF files were loaded.  In ActionScript 3.0, that issue has gone away because the “root” variable now only refers to either the current SWF file or a container in that SWF file (see Part 2 of this tutorial for more details).

To begin, go here and down the “ASTutorial 3.0.rar” file.  unzip it on your desktop. You’ll see a folder called “ASTutorial 3.0.” Inside that folder you’ll see the Preloader.swf and Preloader.fla files. This is our preloader.  You’ll also see folder called “loadedMovie,” and inside that, you’ll see the loadedmovie.fla, loadedmovie.as, loadedmovie.swf, and loadedMovie Project.flp files. The preloader loads the loadedmovie.swf file and that's the only file you need, but keep it inside the "loadedMovie" folder.

If you open Preloader.fla and loadedmovie.fla, you’ll see that their stage sizes are the same.  It is not necessary to do this, but you’ll want that if you want to replace the preloader with the download SWF file.

The main timeline of Preloader.fla has two layers, “actions” and “text.” On the “text” layer, there are two objects, a “circular arrows” movieclip with the instance name “arrows” and a dynamic text field called “percent.” Both objects are on the stage.

If you run preloader.swf, you’ll immediately see an image of the sun shining though some clouds. This image is the loadedmovie.swf, the SWF file that preloader.swf has loaded.

But because loadedmovie.swf is so small, you never saw the preloader run.

To see it run, run the Preloader.swf again (inside the Flash CS3 IDE). Then go to the VIEW menu, select the “Download settings”  item and select “56K.” Then go back to the VIEW menu and select the “Simulate download” item. Now you’ll see the preloader run.

The “circular arrows” movieclip is a just a looped animation that spins the arrows. The “percent” text field shows how what percent of loadedmovie.swf has downloaded. (Make sure that the embedded properties of “percent” are both numerals AND punctuation else you won’t see the “%” sign).

OK, now let’s look at the ActionScript on the “actions” layer.

First, in ActionScript 3.0, we use the “Loader” class to load any external resources into a flash movie.  Therefore, we’ll use it to load our SWF file.  We create a new  Loader:

[as]var loader:Loader = new Loader();[/as]


ActionScript 3.0 Event Handlers

(I’m assuming you know about the new ActionScript 3.0 event manager API so I’ll skip some details here). 

The “loaders” job is to load the loadedmovie.swf file. As the loader “loads” the SWF file (we’ll see how this happens in a sec.), the ActionScript 3.0 event manager will continually fire off a “ProgressEvent.PROGRESS” event.  We want to make sure our “loader” class listens for that event. We do this by using the addEventListener method, and we want to write an event handler to “handle” that event:

[as]loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loop);[/as]

I’ve called the event handler “loop.”  The event manager continually calls this function as the loader downloads the SWF file. This the logical place to track the progress of the download:

[as]function loop(e:ProgressEvent):void
{
var perc:Number = e.bytesLoaded / e.bytesTotal;
var s:String = Math.ceil(perc*100).toString()+"%";
percent.text = s
}[/as]

The ProgressEvent object passed to “loop” contains a variable called “bytesTotal” that holds the size of the loadedmovie .swf file, and “bytesLoaded” tracks how much of it has download each time the “ProgressEvent.PROGRESS” fires. Here I’m converting everything into percent, and I’m assigning that value (in string format) to the “percent” dynamic text field.

But we’re not done yet. When the loadedmovie .swf file is fully loaded, the event manager will then fire off an “Event.COMPLETE” event, so we want our “loader” to the listen for that event too:

[as]loader.contentLoaderInfo.addEventListener(Event.COMPLETE, done);[/as]

“done” is the event handler.  All it does is add the loadedmovie .swf  file to the stage. It also does some clean up:
[as]function done(e:Event):void
{
// 1st) remove each child from the display list so we don’t see them on the stage
removeChildAt(getChildIndex(percent));
removeChildAt(getChildIndex(arrows));
// 2nd) disable any running code in any child (see chap. 14, Moock, "Essential AS 3.0")
arrows.gotoAndStop(1); // stop looping
// 3rd set instance references to null so the garbage collector can remove them from memory
percent = null;
arrows = null;
// finally, add the loader to the stage to display it
stage.addChild(loader);
}[/as]


Loading The SWF File

However, we’re not done yet, right? How do we actually start loading the SWF file?  We need to tell the loader where it is and start the download process. This is the statement we need.

[as]loader.load(new URLRequest("loadedMovie/loadedmovie.swf"));[/as]

So How It All Works

This is what happens step-by-step:

1st) the Preloader.swf starts. The “circular arrows” movieclip is already on the stage, so those arrows start spinning right away. “Percent” is also there, but it’s not displaying anything.

2nd) Flash runtime allocates and creates in memory all the variables and functions defined in our script, i.e., the “loader” object, the “loop” and “done” functions.

3rd) Flash runtime then starts executing our ActionScript 3.0 statements one at a time.  The first two statements are the addEventListener statements. This “wires up,” so to speak, the two event handlers, “loop” and “done,” to our “loader” object.  The next statement is the one that starts the load operations, i.e., “loader.load(new URLRequest("loadedMovie/loadedmovie.swf")).”

4th) Now programme execution is totally under the control the ActionScript 3.0 event manager, i.e., it keeps firing off the  ProgressEvent.PROGRESS event. That causes the “loader” object to call the “loop” function, and the “loop” function is given all the information it needs to tell us how many bytes of loadedmovie.swf have downloaded when the call was made. Finally, when it is completely downloaded, the event manager fires off the Event.COMPLETE event, and that causes the “loader” object to call the “done” function, which displays loadedmovie.swf.

That’s it – it’s that easy.


Part 2. “Dude, the preloader is simple but -- what’s really going on?”

OK, the real story here is the new ActionScript 3.0 Display API. The Display API is one the biggest differences between ActionScript 3.0 and ActionScript 2.0, and what makes this preloader simple is the ease with which ActionScript 3.0 lets us “add” and “remove” objects from the “display list.” (I’m going to assume a basic understanding the Display API and the concept of a “display list.” If not, Rich Shupe & Zevan Rosser have written one of the best introductions to ActionScript 3.0 in their Learning ActionScript 3.0 book. You should definitely pick that up if you’re new to the Display API.

However, let’s very briefly start at the beginning, so we’re clear about the relationships between SWF files, MovieClips, Sprites, and that thing called the “Main Timeline.”

Most flash applications are written with a flash authoring tool, such as Adobe’s Flash Pro CS4.  The flash compiler first converts the .fla file into “ActionScript bytecode” and then it puts that bytecode in a special format called SWF file.  Other programs called “Flash runtimes” execute SWF files.

.fla files can have objects or code in the timeline, and this is called the “main Timeline” of the flash application.


Display List: Display hierarchy

Let’s briefly review the display list hierarchy of the ActionScript 3.0 Display API.  The Display API has three “abstract” classes starting with the “DisplayObject” class. The “InteractiveObject” class directly inherits from the “DisplayObject” class, and the “DisplayObjectContainer” directly inherits from the “InteractiveObject” class:

Core Display Classes Hierarchy
All the other classes you see in the diagram are derived from one of these three “abstract” classes.  These are non-abstract classes, and they are the only classes you can extend.

In a flash application, any object you “see” comes from one of the non-abstract classes, i.e.,  video, bitmap, shape, static text, morphshape, textField, simplebutton, stage, sprite, or movieclip.  The loader class is special in that we can’t “see” it, but it loads one of the other instantiated non-abstract classes that we can see.

So, in our Preloader.fla, how many display objects do we have? We can see that there are two object on the stage, the “arrows” movieclip and the “percent” dynamic text field.  These two objects, either directly or indirectly, from one of the non-abstract class in the above diagram, are automatically instantiated when Preloader.swf runs.

If you click on the ActionScript content in the “actions” layer of Preloader.fla, you’ll see we’re instantiating the loader class:

[as]var loader:Loader = new Loader();[/as]

Now, when the preloader starts, the flash runtime creates in memory all our variables and functions, i.e., the “loader” object, the “loop” and “done” functions defined in our script.

The flash runtime also creates a display list, i.e., a hierarchical list of all visible objects in our flash application.

The root of the display list is an instance of the Stage class. The flash runtime automatically creates it.

Now, all display objects, i.e., our “arrows” movieclip and “percent” dynamic text objects, are displayed at some “depth” in some “display object container,” but what are those depths?

These two trace statements show that the “arrows” and “percent” objects are at depths 0 and 1 respectively in their “instantiated DisplayObjectContainer” object:

[as]trace("depth of 'percent' dynamic text object = "+getChildIndex(percent));
trace("depth of 'arrows' movieclip object = "+getChildIndex(arrows));[/as]

But what exactly is their “instantiated DisplayObjectContainer” object? Is it the stage? A sprite? The Loader? A  movieclip?

In ActionScript 3.0, all “instantiated DisplayObjectContainer” objects  have  a variable called “root.” “root” is just a reference to the  DisplayObjectContainer itself.  Each object in the  DisplayObjectContainer has access to the DisplayObjectContainer’s “root” variable. These two trace statements help us discover what the DisplayObjectContainer is for the “arrows” movieclip and “percent” dynamic text:

[as]trace("the 'percent' object descends/is contained in this specific  DisplayObjectContainer:"+percent.root);
trace("the 'arrows' object descends/is contained in this specific  DisplayObjectContainer:"+arrows.root);[/as]

These statements return:

[as]the 'percent' object descends/is contained in this specific DisplayObjectContainer: [object MainTimeline]
the 'arrows' object descends/is contained in this specific DisplayObjectContainer: [object MainTimeline][/as]

So, the “instantiated DisplayObjectContainer” object  that contains “arrows” and “percent” is the SWF file itself because that has a “main timeline.” (If a .fla file has content in its timeline, the ActionScript 3.0 compiler automatically creates a document class inherited from the flash.display.Movieclip class. If the timeline is empty, it creates a document class inherited from the flash.display.Sprite class ).

The trace statements are telling us the “arrows” movieclip and “percent” dynamic text objects are inside the SWF file, an instantiated movieClip class. This why the trace of "percent.root" &  "arrrow.root" return “MainTimeline” as the container object.

But isn’t it true that the Stage class is always the root of the display list?  Exactly right!

Along with automatically instantiating a movieClip class, the flash runtime engine instantiates a stage class.  The stage object is always the outermost container for all displayable objects like the “arrows” and “percent” objects.

So if a stage object is the root of our display list, what is the first child, if any, at depth 0?  This trace statement gives us the answer:

[as]trace(stage.getChildAt(0)+"is the display object contained inside the stage");[/as]

It returns:

[as][object MainTimeline] is the display object contained inside the stage[/as]

So, from a “object” hierarchy perspective, the instantiated MoveClip class called “arrows” and the instantiated TextField class called “percent” are “inside” the “Main Timeline” object, which is the instantiated MovieClip class of the SWF file.  In the terminology of object-oriented design, this is called “object composition” where one object is “composed” of one or more other objects.

Therefore, we really have only one display list. The deal is that the children are in a “relative” display list (if you will) that starts with the main Timeline (i.e., movieClip) object. In short, the “arrows” and “percent” objects are “contained” in the “Main Timeline” object, which is the instantiated MovieClip class of the SWF file, and the “Main Timeline” object is “contained” in the instantiated Stage class. 

And where is our instantiated Loader class, the “loader” object? 

Well, the “loader” object definitely exists in memory, and from an object hierarchy perspective, it is “inside” the instantiated MovieClip object of the SWF file.

This may be obvious, but from a display list perspective, at the execution point in the script when we create a new Loader object, the “Main Timeline” is NOT considered a “display container” for the “loader” object. However, it is “in” the main Timeline (i.e., movieClip) object, i.e., the main Timeline (i.e., movieClip) object is “composed” of the loader object.

Neither is the “loader” object part of the display list. The “loader” object has access to a “root” variable, but the value of that variable is “null.” For example, this:

[as]trace("the 'loader' object descends/is contained in this specific DisplayObjectContainer: "+loader.root);[/as]

returns this:

[as]the 'loader' object descends/is contained in this specific DisplayObjectContainer: null[/as]

The reason for this is simple: we much add the “loader” object to some container using a method called addChild(), but we’ll get to that in a minute.


ActionScript 3.0 Class, Object and Display List Hierarchies

Quick Aside: let’s talk about three types of “hierarchies,” as you may be getting confused about that.  The “display list” hierarchy is only how the display manager keeps track of what is “displayed” inside what.

Asking what “objects” are derived from or inherited from another object is a different question, and you’re asking about class inheritance or class hierarchy.

Asking if one “object” is “inside” another object is still another question, and it’s a question about “composition,” which is a specific object-oriented design technique.

All three hierarchies are present in this preloader, and it’s important to keep these three types of hierarchies separate in your mind as you’re trying to understand any ActionScript code. 


Adding and Removing Assets from a Container

In Part 1, I went over the “loop” callback function, and everything you need to know is there. However, I want to elaborate on the “done” callback function, as this is where external assets (e.g., movieclips, images, sound files, SWF files, etc) are added and removed from the preloader.

When the “loader” object has fully downloaded loadedmovie.swf, the event manager fires off the Event.COMPLETE event, and that causes the “loader” object to call the “done” function.

Recall that we have two assets in the display list of the main Timeline (i.e., movieClip) object:  the “arrows” and the “percent” objects. We need to remove those now because we want to load the loadedmovie.swf application.  We do this by making a call to the native DisplayObjectContainer method “removeChildAt():”

[as]removeChildAt(getChildIndex(percent));
removeChildAt(getChildIndex(arrows));[/as]

This removes “arrows” and “percent” display objects from the display list of the instantiated DisplayObjectContainer object.

Again, what is the  instantiated DisplayObjectContainer object?

It is the SWF file itself, an instantiated movieClip class. This why the statements “percent.root” and   “arrrow.root” return “MainTimeline” as the container object.

Now, in addition to removing display objects from our container’s display list, we should also remove them from memory. This is because removing objects from the display list simply tells the display manager NOT to display the objects in a flash application – however, they still exist taking up memory in RAM. Most of the time, this is OK, but we know we don’t need these assets anymore, so let’s just get rid of them.

The way we do this is simple: we just set  “arrows” and “percent” to “null,” but – OK, it’s not really that simple.”

When we set a display objects to “null,” we schedule that object for "garbage collection."  Garbage collection is when the memory manager removes “objects” from system memory. However, object removal from memory is up to your operating system and the flash memory manager: they decide when – and if – to claim the memory. In short, garbage collection is not instantaneous when the flash runtime executes the statements that set “arrows” and “percent” to “null.”   

OK, so what’s the big deal?  The deal is that display objects in memory are still “running,” e.g., they can still receive events; if you’ve set up an interval event that triggers processing, that process will continue until the object is removed from memory.  Look inside the “circular arrows” movieclip. You’ll see that it is continually looping from frame 1 to 40. Even though we’ve removed the “arrows” object from the display list, so we can’t “see” it anymore, and we’ve set the “arrows” instance to “null,” if garbage collection doesn’t happen right away, not only does the “arrows” stay in RAM taking up memory, it also continues to loop taking up CPU resources. 

So, we need to make sure all processes have stopped inside the display objects before we schedule them for garbage collection. Here’s the full set of statements in our “done” function:

[as]// 1st) remove each child from the display list
removeChildAt(getChildIndex(percent));
removeChildAt(getChildIndex(arrows));
// 2nd) disable any running code in any child
// (see chap. 14, Moock, "Essential ActionScript 3.0" for more details)
arrows.gotoAndStop(1); // stop looping
// set instance references to null so the garbage collector can remove them from memory
percent = null;
arrows = null;[/as]


Loading the SWF File

At this point, we have two choices. First, we can add the loader to the LoadSystem’s main timeline:

addChild(loader);

This statement adds the loader as a display object child to the SWF file’s main Timeline. The loader is at depth 0 in the display of the main Timeline (i.e., movieClip) object. We know that by from these two trace statements:

[as]trace("the 'loader' object descends/is contained in this specific DisplayObjectContainer:"+loader.root);
trace("depth of 'loader' object = "+getChildIndex(loader));[/as]

they return:

[as]The 'loader' object descends/is contained in this specific DisplayObjectContainer:[object MainTimeline].
depth of 'loader' object = 0.[/as]

Second, we can add the loader to the Stage so it’s at dept 0 in Stage’s child list:

[as]stage.addChild(loader);[/as]

If we use these trace statements:

[as]trace("The 'loader' object descends/is contained in this specific DisplayObjectContainer:"+loader.root);
trace("Object at index 1 is: "+stage.getChildAt(1));
trace("Depth of 'loader' object = "+stage.getChildIndex(loader));[/as]

they return:

[as]The 'loader' object descends/is contained in this specific DisplayObjectContainer:[object Stage].
Object at index 1 is: [object Loader].
Depth of 'loader' object = 1[/as]

So which should we use? Colin Moock in Chapter 20 of Essential ActionScript 3.0 suggests adding it to the Stage.  To be honest, I’m not sure what the advantages or disadvantages are, and this “brief” tutorial is becoming rather long, so since he’s Colin Moock, I’ll just play it smart and follow his example.