Preloaders in AS3

Jan 21 2007 Published by under Brevity, Flash

Send to Kindle

[Note, although this post is right now over a year and a half old, it continues to be one of the most visited pages on my site. If you are just showing up here now, you should note that the data here is a bit dated and may not work exactly as described in the current version of the Flex SDK. In fact, I am pretty sure it DOESN'T work as described anymore. Feel free to read through this for some overall info, but check all the comments as well, which may have more info or links to more up-to-date data. I haven't had to deal with this situation since I first wrote this, so don't have the current method for making AS3 preloaders to hand.]

It’s an age old problem. Let’s go back to AS2: You have a relatively large SWF, consisting of exported movie clips in the library, and/or a good deal of code contained in classes. All classes and exported assets load in prior to frame one being displayed, so the viewer sees nothing while it is all loading in.

Solution: Turn off “export first frame” on your exported assets, and place an instance on some frame in the timeline to force them to be compiled into the SWF. For classes, set classes to export to some later frame. Then put your preloader on frame one, stop the timeline, loop until everything is loaded, then jump to an initialization frame.

Now jump to AS3 with mxmlc. There is no timeline. Embedded assets and all classes load in prior to frame one as in a default IDE-created SWF. So, how do you create a preloader?

Well, if you are using Flex, it’s all programmed in there for you, and while I don’t know the specifics, I know you can specify a custom preloader in Flex, and there is obviously a default preloader in a Flex app. Since the Flex framework is all written in AS3, I knew there must be some way to do this in an AS3 only project, but it wasn’t very clear. In fact, you might say it was rather hidden. My first idea was to check the compiler arguments. These two seemed interesting:

frames.frame label class name [...]
Specifies a SWF file frame label with a sequence of class names that are linked onto the frame.
This is an advanced option.

generate-frame-loader=true|false
Toggles the generation of an IFlexBootstrap-derived loader class.
This is an advanced option.

But that is the entire extent of the documentation on the subject, and doing a web search didn’t turn up a whole lot more.

Then, last Thursday, Ted Patrick happened to be in Boston, and stopped by for a tour of Brightcove. We were sitting there talking to Brian Deitte, who was also part of the Flex team til a few months ago and it occurred to me that one of these guys must have the answer. They pointed me to the [Frame] metadata tag, and said to check out the source for mx.core.Application. Sure enough, I see the following:

/**
* The frameworks must be initialized by SystemManager.
* This factoryClass will be automatically subclassed by any
* MXML applications that don’t explicitly specify a different
* factoryClass.
*/
[Frame(factoryClass="mx.managers.SystemManager")]

And, checking out SystemManager, I see a few interesting tidbits:

// NOTE: Minimize the non-Flash classes you import here.
// Any dependencies of SystemManager have to load in frame 1,
// before the preloader, or anything else, can be displayed.

and

* The SystemManager is the first display class created within an application.
* It is responsible for creating an mx.preloaders.Preloader that displays and
* mx.preloaders.DownloadProgressBar while the application finishes loading,
* then creates the mx.core.Application instance.

And finally, the create() method, which is basically called when the movie is fully loaded in:

[as]
public function create(… params):Object
{
var mainClassName:String = info()["mainClassName"];

if (mainClassName == null)
{
var url:String = loaderInfo.loaderURL;
var dot:int = url.lastIndexOf(“.”);
var slash:int = url.lastIndexOf(“/”);
mainClassName = url.substring(slash + 1, dot);
}

var mainClass:Class = Class(getDefinitionByName(mainClassName));
return mainClass ? new mainClass() : null;
}[/as]

A bit more searching around led me to this post by Roger Gonzalez, which explains it a bit more, though highly oriented towards Flex. Even he describes the Frame tag as “semi-secret and bizarre”. :) He also mentions that it is basically an inline alias for the “frames” compiler configuration option. So, with a bit more work I could probably figure out how to do it that way, but the metadata way seems easier so far.

This was enough for me to start testing in AS3 only. Here’s the deal:

First you create your main class as usual, and point the compiler to that as the class to compile.

You then use the [Frame] metadata tag, passing in another class as the factoryClass, like so:

[Frame(factoryClass="MyFactoryClass")]

This is where the magic happens. Basically, the Frame tag forces the compiler to create a two-frame SWF. All of your embedded assets, your main class and any classes that are used by the main class are forced into frame two. The only thing that goes into frame one is your specified factory class and any classes or embedded assets that it uses. Hence the above warning to include minimal other classes in this class.

So, this factory class is where you create your preloader. Generally, you want to stop the timeline, and then set up an enterFrame listener, or a timer to check currentFrame against totalFrames. When they are equal, it means that the rest of your classes and assets are loaded in and ready to go. You then want to call nextFrame() to move to frame two so those classes and assets will be available. At that point, you can instantiate your main class, using getDefinitionByName(). This allows your factory class to create a new instance of the main class without compiling a reference to that class into it – which would force the main class and everything else to load in frame one and defeat your preloader.

The slightly weird thing about this setup is that you are usually used to your main class being the “document class”. That is, the main class represents the main timeline of the SWF. In this setup though, the factory class actually becomes the document class. This has a few ramifications:

  1. The factory class has to extend MovieClip. NOT Sprite! It actually has frames, so it should be a MovieClip.
  2. When you create an instance of your main class, you then have to do an addChild to get it onto the display list.
  3. Your main class will not be the at the base of the display list. It will be a child of your factory class.
  4. Because you instantiate your main class, and THEN add it to the display list, be careful not to have its constructor call code which will refer to stage, as its stage property will not be available until after it is added.

OK, let’s look at an example. First we have the main class, which we will target with mxmlc:

[as]package {
import flash.display.Sprite;
import flash.display.Bitmap;

[Frame(factoryClass="com.bit101.MyFactory")]
public class FrameTest extends Sprite
{
[Embed(source="big_asset.jpg")]
private var Asset:Class;

public function FrameTest()
{
init();
}

public function init():void
{
var asset:Bitmap = new Asset();
addChild(asset);
}
}
}[/as]

This doesn’t do much other than embed a large jpeg image, which makes the SWF come in at over 3 MB. If you were to compile this normally, the end viewer would see a blank screen until that jpeg fully loaded in. But the addition of the line:

[Frame(factoryClass="com.bit101.MyFactory")]

causes the main class, along with the embedded jpeg, to go into frame two. Note that in this case it is safe for the the constructor to call the init function directly. But, as mentioned earlier, you might want to delay that until the instance is actually added to the display list, to avoid null stage references, etc.

Now let’s look at the factory class:

[as]package com.bit101
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.utils.getDefinitionByName;

public class MyFactory extends MovieClip
{
public function MyFactory()
{
stop();
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

public function onEnterFrame(event:Event):void
{
graphics.clear();
if(framesLoaded == totalFrames)
{
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
nextFrame();
init();
}
else
{
var percent:Number = root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal;
graphics.beginFill(0);
graphics.drawRect(0, stage.stageHeight / 2 – 10,
stage.stageWidth * percent, 20);
graphics.endFill();
}
}

private function init():void
{
var mainClass:Class = Class(getDefinitionByName(“FrameTest”));
if(mainClass)
{
var app:Object = new mainClass();
addChild(app as DisplayObject);
}
}
}
}[/as]

Note that it extends MovieClip. It immediately stops the timeline and adds an enterFrame listener. In that handler, it checks to see if framesLoaded == totalFrames. If so, it calls nextFrame() to make the main class available, and then calls init, which gets a reference to the main class, instantiates it, and adds it to the display list.

While second frame is still loading, it simply draws a progress bar on the stage, using root.loaderInfo.bytesLoaded and root.loaderInfo.bytesTotal to access the percent loaded.

This is a pretty simple example, but shows you how it works. I’m pretty sure it’s the only documentation out there on how to do this in AS3, so feel free to share it around.

Send to Kindle

133 responses so far. Comments will be closed after post is one year old.

  • Tink says:

    Nice handy find!

  • Good post Keith. Thanks.

  • sascha/hdrs says:

    Keith to the rescue! I take it you have read my comment posted lasted week! I’ve also tried the compiler arguments but as Flex doesn’t need them I thought there must be another way. However the stuff with the factory class was confusing me and the docs are not help at all in this case. Thanks for this great explanation! btw is -generate-frame-loader deprecated? It doesn’t appear in the compiler arguments list when using mxmlc -help advanced. Just wondering.

  • William from Lagos says:

    Great Keith. And thanks for sharing.

    BTW, I’m loving your book (3 Cookbook), so much!

  • Ash says:

    Bookmark’d!

  • andy makely says:

    This works great! Thanks!

    How is it that the getDefinitionByName(“FrameTest”) is able to resolve the class? Usually it throws an error if the desired class has no previous reference…

  • sascha/hdrs says:

    Tried it, works great but I get one odd thing with this approach: A ‘Default CSS file not found’ warning. Any ideas why this is happening? I never got this warning in an AS project before.

  • liuhuan says:

    Really useful, thanks a lot!!!

  • Den Ivanov says:

    Very nice article. Thanx. Who know how many “semi-secret and bizarre” they have in their pockets? ))))

  • Sascha/hdrs: You’re using a Flex component without defining your Application in MXML, right? The MXML compilation process auto-generates a bunch of code, including that style class you’re missing. When a Flex component is initialized, it expects those auto-generated classes to exist, but they won’t if you’ve written your application in AS3 (no MXML).

    The only way around this (AFAIK) is to define your base Application class in MXML, and then load in your AS3 classes on creationComplete. Either that, or don’t use Flex components :) .

  • [...] Keith Peters posted a really detailed write-up of how to use this tag for preloading a few months ago. Basically, the deal is that you can use this tag to force the compiler to create a two-frame SWF file. ActionScript: [...]

  • sascha/hdrs says:

    Nathan thanks but I also get this warning even though I don’t use a single Flex2 component in my app. The odd thing is that the warnings will even double and triple after a while of compiling. So I get 2 or 3 of the same warning.

  • Austin Haas says:

    getDefinitionByName() was throwing an error for me, but simply importing my main class and changing init() to:
    private function init():void{
    var app:Object = new MyMainClass();
    addChild(app as DisplayObject);
    }

    worked fine.

  • Austin Haas says:

    Crap. Scratch my last comment. By using the class name directly, instead of getDefinitionByName, I was causing the class and all of it’s dependencies to be loaded from the start, bypassing the whole purpose of the preloader.

    I got the getDefinitionByName() to work by adding the package name onto the quoted class name. I don’t know if that has something to do with my mxmlc compile command or what.

  • ej says:

    thanks for the useful information.

    when i try this though, the size of my app jumps from 80k to 190k. I even stripped your preloader class down to basically nothing, importing just movieclip, displayobject, and event.

    also interesting, when i remove the frame command, and just import the preloader class into the Main class it does not jump to 190k.

    so im guessing flash imports a bunch of flex stuff when you add the frame command?? is there any way to find whats getting imported or stop this?

  • Bart says:

    Thanks for the post. It helped my to make a good preloader.

    You mentioned that I cannot refer to the stage in my main class. So, can you give me a hint on how to make a stage listener then, i still hope this is possible?

    Thanks for any reactions

  • Kris says:

    This code works fine for me…

    package {

    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.events.Event;

    [Frame(factoryClass="com.bit101.MyFactory")]

    public class FrameTest extends Sprite {

    [Embed(source="big_asset.jpg")]
    private var Asset:Class;

    public function FrameTest() {
    addEventListener(Event.ENTER_FRAME, onEnterFrame);
    }

    public function onEnterFrame(event:Event):void {
    // if root != null then the Factory Class is loaded and you can use stage
    if (root != null) {
    removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    init();
    }
    }

    public function init():void
    {
    var asset:Bitmap = new Asset();
    addChild(asset);
    asset.x = (stage.stageWidth – asset.width) / 2;
    asset.y = (stage.stageHeight – asset.height) / 2;
    }
    }
    }

  • RT says:

    Does this apply to swf’s created in the Flash CS3 authoring environment, or some other form of actionscript 3.0 coding? It’s hard to believe this is the way to get a progress bar to load before all other content in an swf. Why can’t the developers of Flash just create a straight forward way to accomplish such an essential task?

  • Tink says:

    @RT

    No this is for ActionScript 3.0 projects created with Flex Builder not Flash CS3.

    In Flash you can just place all your assets on frame 2 of your main timeline just like you could in previous versions of Flash.

  • Tink says:

    @Bart and Kris

    You can listen for Event.ADDED_TO_STAGE

  • Tink says:

    “Your main class will not be the at the base of the display list. It will be a child of your factory class.”

    I’ve just implement this method in a project (as you can see I was looking at this post last night) and decided to add the main class to the display list of the preloaders parent i.e.

    private function create():void
    {
    var MainClass:Class = Class(getDefinitionByName( “MainClass” ) );
    var mainClass: DisplayObject = new MainClass();
    parent.addChild( mainClass );

    parent.removeChild( this );
    }

    Doesn’t seem to cause any problems but I also get the warning “Default CSS file not found” (in fact i have it twice), and this is a pure AS 3.0 application (i.e. no Flex).

  • DeceptiveResolution says:

    Here’s something i made for Flash CS3:
    http://deceptiveresolution.wordpress.com/2007/08/01/flash-cs3-preloading-stage-assets-external-classes-is-this-a-useful-hack/

    I thought it might be relevant to this thread. Any suggestions will be greatly appreciated.

    Regards

  • sascha/hdrs says:

    Just found out today that just by simply putting something like [Frame(factoryClass=”com.bit101.MyFactory”)] before your class makes the resulting SWF approx. 130Kb large. Anyone else who can confirm this? 130Kb are usually a bit too much for a preloader so this renders this method for a preloader rather useless!

  • kp says:

    it shouldn’t add that much. sounds like you are getting some flex stuff into your factory. you gotta make sure you really limit what you access in that class.

  • sascha/hdrs says:

    Keith, I’ve tried it. I’ve made a basic class and as soon as I add [Frame(factoryClass=”… the SWF becomes 130Kb. First I though it’s because of my preloader class which also uses some other classes. But I’ve commented out all related stuff and even without it and only the [Frame… line before the class it results in 130Kb.

  • Al Lemieux says:

    Thanks for doing this!!! I pared down your example to its strict basics and got it to work. One question: what’s the benefit of registering the movie clips in the class as opposed to having Flash automatically detect them?

  • Al Lemieux says:

    I’m getting an error only when I test at DSL or T1 speeds. It doesn’t happen at 56k. Here’s the error:

    TypeError: Error #1009: Cannot access a property or method of a null object reference.

    The preloader works and when it’s complete it takes me to the correct frame, which has a stop action. I’m wondering if the enterFrame event isn’t being properly removed?

  • [...] BIT-101 Blog comments [...]

  • Francis Gabon says:

    Thanks for that soooo useful tip :) It’s a shape that there is no relevant doc about those compiler options.

    Nevertheless, I got the same errors as Al and Sascha: my SWF is now 130kb bigger, and when testing bandwidth with Sloppy Java applet, I got the TypeError #1009. Any clues about that, Keith?

  • Francis Gabon says:

    erratum: “it’s a SHAME…” :p

  • kris says:

    My swf-file is 4.4K when compiling with flex 2 (eclipse plugin). I tried compiling the same source with mxmlc (flex2sdk) and the swf-file is 129K !!!???

  • kris says:

    This mxmlc compiler option solved the problem :

    -verbose-stacktraces=false

  • eka says:

    I try this, and works , but i cant see the bar … is like it’s loading everything before even start in frame 1

    any clue?

  • Matthias says:

    Hello Keith,

    I found recently also the Frame meta tags when compiling an MXML based project using -keep compiler option and I came across the following meta tags:
    [Frame(extraClass="_CustomPreloader_FlexInit")]
    [Frame(factoryClass="_CustomPreloader_mx_managers_SystemManager")]

    I also found these interesting lines in the Flex Framework that are related to this topic:

    sdks\2.0.1\frameworks\source\mx\core\FlexModuleFactory.as (94): addFrameScript(docFrame, docFrameHandler);
    sdks\2.0.1\frameworks\source\mx\core\FlexModuleFactory.as (94): addFrameScript(docFrame, docFrameHandler);
    sdks\2.0.1\frameworks\source\mx\core\FlexModuleFactory.as (94): addFrameScript(docFrame, docFrameHandler);
    sdks\2.0.1\frameworks\source\mx\core\FlexModuleFactory.as (96): // Frame 1: module factory
    sdks\2.0.1\frameworks\source\mx\core\FlexModuleFactory.as (97): // Frame 2: document class
    sdks\2.0.1\frameworks\source\mx\core\FlexModuleFactory.as (98): // Frame 3+: extra classes

    So my questions here are:
    * Do you know when to use “[Frame(extraClass=”?
    * Is the document/main class really on Frame 1 and the Factory on Frame 2?
    * Why do I still get the “Default CSS file not found” warning? I don’t want to use the Flex Framework in one of my AS3 only projects, so I need no Default CSS or the like..

    Matthias

  • [...] Keith peiters has a wonderful tutorial on how to preload in an AS3 only project. I had been wondering myself but had just been cheating and having my as3 app sitting in a flex app. [...]

  • eka says:

    Hi all
    i found out that It’s working… thanks, but i get a yellow frame like focus that when i click it disappear… or when doing tab… i tried with focusRect = null etc… and still there… any clue?

  • [...] Wenn man mit Flex arbeitet muss man sich um den Preloader icht kümmern. Wie man aber selbst einen Preloader erstellt, wenn man nur ein reines AS-Projekt hat wird hier beschrieben. Search [...]

  • baec says:

    Hi Keith and all,

    Thanks, super help. Worked. Cleaned lotsa things up. I also get the “no default CSS” warning.
    One question though, just cant figure it out …

    in the flex SystemManager create method you have posted above there is the line -


    var mainClassName:String = info()["mainClassName"];

    further down in that SsytemManager class i found a very cryptic -


    public function info():Object
    {
    return {};
    }

    so where does that info object get populated ? that bit allows them to have a generic system manager and only send it a different main class name. but how can they set that info before anything loads ?
    the only thing i can think of is that it has something to do with the flex compiler since i have noticed the info object contains other tags for stuff set as compiler options or mxml settings ( backgroundColor etc ) ?! anyone ?

    ~:(

  • RubenDoliveira says:

    Hi all,

    I’m getting this error, what I’m doing wrong?

    ReferenceError: Error #1065: Variable FrameTest is not defined.
    at global/flash.utils::getDefinitionByName()
    at classes::preloader/::init()
    at classes::preloader/onEnterFrame()

  • H7 says:

    AS 3.0 is very poorly documented in my opinion. I am glad this works for you, but I have no idea on how to test it… I suppose it would be nicer if this kind of tutorials would be more beginner oriented…

  • pedro says:

    Thank you, you just saved me a lot of fiddling :)

  • sascha/hdrs says:

    Kris: “This mxmlc compiler option solved the problem : -verbose-stacktraces=false”

    … Kris this is not working for me. No matter what I do it always add up ~110Kb when I use this preloader method. Any other ideas why the file size gets so bloated?

  • erixtekila says:

    TIP :
    If you want to save a bunch a bytes in your generated swf code, beware of using the flex.swc and utilities.swf as library (-library-path)
    WARNING : There seems to have a subtle difference between the flex2 and flex3 command line option :
    -compiler.library-path alias for flex2 is -l
    -compiler.library-path alias for flex3 is -library-path

    Maybe the weight problem of sascha/hdrs…
    HTH

  • sascha/hdrs says:

    Thanks erixtekila! Yes I have found this out yesterday (see here http://www.actionscript.org/forums/showthread.php3?t=152148 ). It’s just strange that the Flex stuff gets included even though it is not really reffered in the compiled code.

  • roflmao says:

    i get the same error as RubenDoliveira is flash cs3…
    Austin Haas has solved it somehow, but i can’t get it running. somebody can help me please?

  • erixtekila says:

    You’re welcome, Sascha !
    I use a different setting than the url you’ve posted.
    Note that mine work with the last release of flex 3 beta 2.

    I keep playerglobals.swc as an external-lib (like you can see in the Adobe’s flex-config.xml) and set the complete path to utilities.swc and flex.swc
    That way only the depencies of the flex framework are bundled in the swf. The weight comes from that side if you check in the swf bytecode.
    See you in the FDT forum ;)

  • [...] The last days I was playing around with the Flex Metadata Tag “Frame” to implement a preloader in an AS3 project. You might have read Keith Peters post concerning this issue. This method is working fine, except of the fact that I can’t get rid of the flex framework classes in my compiled SWF, which blows up the size of an nearly empty SWF to 120kb. If you check out the comments in his post, you’ll find a few solutions, but none of them worked for me. So I generated a XML exclude File, that excludes the whole flex framework. You might want to give it a try: flex_framework_exclude.xml (compile with the option -load-externs+=flex_framework_exclude.xml). It’s still not satisfying, but it’s working… [...]

  • [...] The class “Test” acts as the factory class that’s responsible for the preloading. The Class “Demo” is the main application class. Using the compiler option -frame frameLabel Demo, the class Demo is compiled into frame 2. Just like in Keith Peter’s Example and my try using and exclude xml, you can preload a pure AS3 application now, but in this case no flex framework classes are compiled into the resulting SWF and there is no need for an exclude xml. Finally! [...]

  • Akewea says:

    Wonderful !

    It’s just what i was looking for ! :)

    Thanks for all ! I thing I’ll put a quick French translation on my blog, if you agree.

    Akewea

  • jawele says:

    first of all thx for the tutorial!

    I’m sure there must be a way to do it without screw up the “root” object….

  • Scott says:

    I found a way to get rid of that annoying “default css file not found” warning. I’m still not sure why it even happens, but if you put a file called “default.css” in the same directory as your main .as file, and then set the following compiler option it works:

    defaults-css-url “default.css”

    I used to get another warning added to the list every time I compiled like many others had mentioned, but now it seems to be gone for good! My default.css file is empty BTW.

  • Ed says:

    For anyone getting a ReferenceError: Error #1065: Variable [some variable] is not defined

    Make sure you’re specifying your main class (the one containing “[frame(factoryClass=...]“) as the compile target — NOT the preloader class.

    That frame metadata tag instructs the compiler to look up the specified class automatically.

  • Ed says:

    Found a simpler solution on http://www.nulldesign.de/2007/11/30/as3-preloading-continued/

    The following is copied directly from that page:

    “I wasn’t really satisfied with the solution I used for my AS3 preloader (see post: Preloader in AS3 projects). Now Sven found THE solution. It’s in german, so I try to explain how it works:

    “The class “Test” acts as the factory class that’s responsible for the preloading. The Class “Demo” is the main application class. Using the compiler option -frame frameLabel Demo, the class Demo is compiled into frame 2.

    “Just like in Keith Peter’s Example and my try using an exclude xml, you can preload a pure AS3 application now, but in this case no flex framework classes are compiled into the resulting SWF and there is no need for an exclude xml. Finally!”

  • Can you help me with a preloader on this http://www.alphachurch.org/worshipg1tough.htm I’m in the dark on as3 and need a visual example to proceed, if you have time to help me. Thanks, Patricia

  • Ruy Adorno says:

    Great solution! And the comments have a lot of good stuff too! Keep’on with the good work!

  • Markus says:

    I am working with Flex Builder 3 Beta and when i tried out the to put the [Frame… tag in my code, then i get the following errors:

    - Unable to resolve resource bundle “core” for locale “en_US”
    - Unable to resolve resource bundle “effects” for locale “en_US”
    - Unable to resolve resource bundle “skins” for locale “en_US”
    - Unable to resolve resource bundle “styles” for locale “en_US”

    I don’t even know what is the meaning of “locale”?!?
    Please help

  • [...] is German, but the source code is readable). Also thanks to Lars Gerckens for his research, and BIT-101 for this alternate solution. And of course thanks to Adobe for providing such horrendously incomplete documentation that things [...]

  • Adept says:

    I wrote up a description of another way to to this here: http://www.jetpackhq.com/blog/2008/03/25/writing-a-preloader-in-actionscript-3/

    However I’m running into another problem: in a web browser, not standalone, bytesTotal appears to represent the total bytes in the first frame, rather than the total bytes in the SWF. Any ideas?

  • Adept says:

    From looking at the source code to mx.preloaders.DownloadProgressBar, Adobe’s own code actually has to guess at the size of the SWF it’s loading. Weak. So no “percentage loaded” indicator is going to be accurate unless you explicitly provide it with the estimated size of your SWF. :(

  • newton says:

    would you tell me how i can do this preloading in document class in flash, i fear about the extra 110 kb of flex that load up even if i do nothing, so i need a work around in flash it self.

  • Chris says:

    How does this show a progress bar? It only updates the progress on Event.ENTER_FRAME, which only happens once.

    Btw, I think this guy plagiarized you: http://www.dreaminginflash.com/2007/11/13/actionscript-3-preloader/#comment-274

  • Chris says:

    Weird, upgraded to the Flex 3 SDK on Linux, and now ENTER_FRAME is called repeatedly, as it’s supposed to.

  • [...] If you stumbled upon this page but don’t understand German, a good starting point for you is Preloaders in AS3 by Keith [...]

  • Zir0 says:

    Hey.

    I made a simple code as you have here, but my percentage is always 100%, throughout the entire duration of the preloader.

    When I trace bytesLoaded and bytesTotal, it turns out that bytesTotal is always the same value as BytesLoaded, and BOTH numbers are reflecting the number of bytes loaded. :-/

    Any ideas?

  • ac says:

    for my testing of keith’s code above, the result is same as what Zir0 observed.
    frame 1 and frame 2 always loaded together at the same time.
    framesLoaded == totalFrames always true,
    and bytesTotal is always the same value as BytesLoaded.

    my development tool is only flex_sdk_3′s mxmlc.exe.
    my testing environment is: IE6, win2k, flash10.ocx.

    which development tools are you guys using?
    any idea?
    thx.

  • marc says:

    Error #1065: Variable [some variable] is not defined.
    metadata is not for flash IDE, it will be ignored.

  • [...] before next Sunday. Though, I have managed to make a pure AS3 preloader for the game, thanks to This post on Bit-101 Blog. Other than that… Ah yes, I’ve been working for two days on a little, [...]

  • Your site is about the only thing I’ve been able to find to offer guidance on this subject. Thank you for creating the web site. I hope you can help direct me toward additional information and/or places where I can find more of this info.

  • [...] AS3 only preloader is heavily borrowed from the one described at bit-101. If you’re interested in the technical reasons for why this preloader works, then I would [...]

  • [...] Este post es una adaptación traducida al castellano de un post de bit-101. [...]

  • Kaleb Wyman says:

    @Those with the “Default CSS not found” error message.

    Not sure if this is recommended, but if you open up the .actionscriptProperties and comment out…

    such as…
    <!—->

    …this stops the “default css file not found” error message as well.

  • [...] Keith Peters posted a really detailed write-up of how to use this tag for preloading a few months ago. Basically, the deal is that you can use this tag to force the compiler to create a two-frame SWF file. [...]

  • [...] 源文出处:http://www.bit-101.com/blog/?p=946 [...]

  • wangkang says:

    there is an alternative solution for those projects not built by FlexBuilder:

    http://www.ghost23.de/blogarchive/2008/04/as3-application-1.html

  • [...] Este post es una adaptación traducida al castellano, a petición del público, del método que nos muestran en este post de bit-101. [...]

  • Larry says:

    can we use

    stage.addChild(app as DisplayObject);

    at line 45 in factory class?

    I think this makes the “display tree” more clear and independent.

  • felix says:

    Been using this method for a while now with no problems. However I just observered a bug when using it with swfaddress 2.2. For some reason the preloader does not show when deeplinking into a page. Loading the main URL (with no #) shows the preloader as usual.

  • felix says:

    regarding my comment above – just found the solution here: http://sourceforge.net/forum/message.php?msg_id=5057312

  • [...] lo más importante cómo hacer la precarga del proyecto sin usar el Metatag Frame, (método originario de Mike Chambers) ya que esto impide que desde CS4 compile bien. En este caso me baso en este [...]

  • [...] working in an Actionscript Only Project without having to include any of the flex project. Bit 101 http://www.bit-101.com/blog/?p=946 has a post about using the frame metatag but unfortunately all my attempts to use it resulted in at [...]

  • [...] to OOP: A nice introduction to explaining the basics of Object Oriented Programming. 5.) Pre-loaders with AS3: One developers take on how to implement a pre-loader using AS3 (often an annoying [...]

  • [...] This is a pretty simple example but I hope it shows you how it works. Aside from my solution, I found a few articles on the topic, with the most promising being this one from Ted on Flex. [...]

  • Erik says:

    Any good references or suggestions how to load in RSLs with this spproach?

  • Geraint says:

    Anyone know why this would not work in firefox but be fine in IE?

    Thanks for your time
    Geraint

  • achidutsu says:

    To Erik
    Any good references or suggestions how to load in RSLs with this spproach?

    package com.netBrothers.service
    {
    import flash.display.DisplayObject;
    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLRequest;
    import flash.system.ApplicationDomain;
    import flash.system.LoaderContext;
    import flash.utils.getDefinitionByName;

    public class appLoader extends MovieClip
    {
    // Массив адресов библиотек
    protected var libs:Array;
    // Индекс текущей библиотеки для загрузки
    protected var libsLoadIndex:Number;
    // Loader для загрузки библиотек
    public var libLoader:Loader;
    // Имя класса основного приложения
    protected var mainApplicationClassName:String;

    // Запишем время старта и окончания загрузок
    protected var preloaderInitTime:Number;
    protected var loadAppCompleteTime:Number;
    protected var loadLibsCompleteTime:Number;

    public function appLoader(libs:Array, mainApplicationClassName:String)
    {
    preloaderInitTime =
    (new Date()).getTime();

    this.libs = libs;
    this.mainApplicationClassName =
    mainApplicationClassName;
    libsLoadIndex = 0;

    // Инициализируем загрузчик
    libLoader = new Loader();
    libLoader.contentLoaderInfo.addEventListener(Event.INIT, libLoaderInitHandler);
    libLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, libLoaderErrorHandler);
    libLoader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, libLoaderErrorHandler);

    stop();
    stage.scaleMode = StageScaleMode.NO_SCALE;
    stage.align = StageAlign.TOP;
    addEventListener(Event.ENTER_FRAME, onEnterFrame);
    }

    // Вызывается при окончании загрузки .swf файла
    // главного приложения
    protected function init():void
    {
    nextFrame();
    var mainClass:Class = Class(getDefinitionByName(mainApplicationClassName));
    if (mainClass)
    {
    var app:Object = new mainClass();
    addChild(app as DisplayObject);
    }
    }

    // Начинает загрузку библиотек
    public function loadLibs():void
    {
    loadAppCompleteTime = (new Date()).getTime();
    if (libs && libs.length > 0)
    loadLib();
    else
    libsLoaded();
    }

    // Загрузка текущей (libsLoadIndex) библиотеки
    protected function loadLib():void
    {
    var urlRequest:URLRequest = new URLRequest(libs[libsLoadIndex]);
    var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
    libLoader.load(urlRequest, loaderContext);
    }

    protected function libsLoaded():void
    {
    loadLibsCompleteTime = (new Date()).getTime();
    init();
    }

    // event handlers

    protected function libLoaderInitHandler(event:Event):void
    {
    libsLoadIndex++;
    if (libsLoadIndex == libs.length)
    libsLoaded();
    else
    loadLib();
    }

    protected function libLoaderErrorHandler(event:Event):void
    {
    trace(“libLoaderErrorHandler: ” + event);
    }

    public function onEnterFrame(event:Event):void
    {
    graphics.clear();
    if(framesLoaded == totalFrames)
    {
    removeEventListener
    (Event.ENTER_FRAME, onEnterFrame);
    loadLibs();
    }
    else
    {
    var percent:Number = root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal;
    graphics.beginFill(0);
    graphics.drawRect(0, stage.stageHeight / 2 – 10, stage.stageWidth * percent, 20);
    graphics.endFill();
    }
    }
    }
    }

  • shaman4d says:

    Thank you, its very usefull solution. Could you please explain what different among it and -frame start (option compiller) solution? Sad but workaround with “Default CSS file not found” problem spend little more time for project setup.

  • christian says:

    A bit disappointing the file gets 36kb bigger, despite there are not assets or external classes imported in the factory class. But definitely a very handy technique. Thanks!

  • [...] you really don’t need the timeline to build a preloader. The technique is described in detail at bit-101. In short it works like [...]

  • [...] Peters’ recommended this method for those who are using mxmlc (usually via Eclipse/FDT or FlashDevelop) to compile their code. I [...]

  • Nick Wiggill says:

    For those looking for the solution to the getDefinitionByName() problems, and realised they couldn’t use a reference to class or they’d defeat the whole purpose of the preloader, look no further:

    1. Import your main application class in your factoryClass with a normal import statement.

    2. To ensure the import statement is not optimised out by the compiler (due to it not being referenced in the normal way), go and change your mxmlc compiler options, using the following additional switch to force the import you created above:

    -includes=com.mysite.Main

    And ensure, of course, that that same class is imported in

    Many, many thanks go to Matthias Eichstedt over at Mike Chambers’ blog ( http://www.mikechambers.com/blog/2006/06/22/actionscript-3-get-a-class-reference-by-class-name/ ) for pointing this out. And of course to Keith for digging this grand solution out of the minds of the Adobe guys :)

  • Nick Wiggill says:

    Oops, please ignore the line in my above post that says, “And ensure, of course, that that same class is imported in” — that was just cruft I forgot to delete. 1 and 2 are the only steps needed to get this working.

  • Tamas Gronas says:

    It works! Thank you!

  • [...] the two event dispatcher methods could be attached. I remembered reading in an excellent article by Bit 101 how using a [Frame] metadata tag would force your application to have two frames. This seemed to be [...]

  • I have another use for the [Frame] Metadata Tag which may be of interest: http://alecmce.com/as3/replacing-enter_frame

    The solution was inspired by a memory of this post – many thanks.

  • acidleaf says:

    Thanks alot! Finally a solution to my problems.

  • dbam says:

    i used to use the tag in ANT build.xml, targeting the “Not-Really-FactoryClass”.
    Worked like that for preloaders…
    But with the [FRAME(factoryClass="")] style i could get RSLs to compile using ANT.

    to achidutsu@91:
    i’m using this to make it work, compiling the DocumentClass (including the factoryClass frame tag):
    public class FactoryClassRSL extends MovieClip {
    private var _go:Boolean = false;
    private var _RSLLoader:Loader;

    public function FactoryClassRSL() {
    stop();
    loadRSL();
    addEventListener( Event.ENTER_FRAME, onEnterFrame );
    }
    private function loadRSL():void {
    _RSLLoader = new Loader();
    var request:URLRequest = new URLRequest(“RSL.swf”);
    var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
    _RSLLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, RSLcompleteHandler);
    _RSLLoader.load(request, loaderContext);
    }
    private function RSLcompleteHandler(event:Event):void {
    _go = true;
    }
    private function onEnterFrame( event: Event ):void {
    if( framesLoaded == totalFrames && _go ) {
    removeEventListener( Event.ENTER_FRAME, onEnterFrame );
    init();
    }else {
    var per:int = Math.round( stage.loaderInfo.bytesTotal / stage.loaderInfo.bytesLoaded ) * 100;
    }
    }
    private function init():void {
    nextFrame();
    var mainClass:Class = Class( getDefinitionByName( “DocumentClass” ) );
    if ( mainClass ) {
    var app:Sprite = new mainClass(stage);
    addChild( app );
    }
    }
    }

    Be sure to use the
    -compiler.external-library-path
    and
    -runtime-shared-libraries
    compiler command line options, to set up resources for compile-time.

    cheers, and good coding!

    ps.:Keith for president! it’s 2010, and this post is KEEPING it’s value…
    a tipical “yesterday’s jam” – lasting for ages.

  • Andreas says:

    I can’t get this to work. The factory class won’t be instantiated until the entire swf is downloaded.

    • bichodigital says:

      you are probably referencing the main class in your preloader. I’ve read this in other blog post about this technique:
      “Just remember, everything that the preloader references will be loaded before the preloader can be shown, so keep it to a minimum.”
      This blogpost needs to have that warning on it.

  • Stephen says:

    Excellent. Just what I was looking for. Thanks for detailing this!

  • [...] 当时想到的解决方法就是要移除文档类的import语句。然后网上一搜,发现bit-101早在N年前就讲了类似的方法。他那里针对的是纯AS3项目的,通过用Flex里面的一个Frame标签,使生成的swf包含两帧。那篇文章后面的comment里面,有人说会将Flex框架也带进编译出来的swf文件里,从而增大体积。不过我自己测试了一下,也没发现有这个问题。只是由于用了Embed标签,增加了几个Flex的类。 [...]

  • [...] 于是我翻出以前bit-101上的一片经典的as3自身加载的文章:Preloaders in AS3,仔细看看后,发现原来的想法是正确的,只不过在flex中靠的是元数据标签Frame来增加一个工程关键帧类factoryClass,而这个类在flex项目中默认为mx.managers.SystemManager,并由此控制flex程序的preloading实现。说白了,就是flex程序的其实都是2帧,第一帧默认是SystemManager类的实例,第二帧才是我们的Application文档类mxml。再进一步查看flexçš„as3 compiler的源程序,也证实了这点。 [...]

  • Morris says:

    Actually,there’s an easier way.Add compiler argument “-frame start Main” or “-includes Main”.The former binds Main Class to a frame named “start”,the later just ensure exporting Main Class.In either way,you o won’t get Runtime Error when you try to use
    var mainClass=getDefinitionByName(“Main”);So you don’t have to add the [Frame] tag.
    I wrote a post in my blog.http://warwithinme.com/2010/04/preloader-in-pure-as3-project/But you might not be interested in,cause it’s written in Chinese.

  • [...] AS3 application compiled with mxmlc. I couldn’t find much documentation on the topic but this post by Kieth Peters describes the solution in good detail, except his post is some what old and the code there [...]

  • Alex says:

    It works great in FlashDevelop, but is it possible to get it to work in Flash CS4 IDE?

  • Whoa ! That’s a very helpful explanation !! Thank you very much :)

  • ZREN says:

    Thanks, it’s very helpful for me.
    http://www.as3tutorial.com is very helpful for beginners.

  • [...] around for while, I went back to follow some the links from Josef’s post which lead me to here, where I noticed this page and this line in particular. . . . The root class is actually a [...]

  • Nick says:

    One workaround for the default css not found is just creating an empty defaults.css in the src folder for your application.

  • [...] we need to use this factory. Following a similar method to creating a preloader we will use the Frame metadata. However, we can’t exactly follow this. In a seemingly odd [...]

  • Hi,

    I have a custom SystemManager class properly instantiating my application to show a preloader within a 1-swf Flash game. All good.

    Something I can’t figure out is a way to have my document class (where the Frame tag exists), set a property that the SystemManager can read? Can I…

    1) Send a variable through the Frame tag?
    2) Read a variable from the SystemManager constuctor from the main constructor class? Dynamically (i.e. not hardcode the name of the main class)

  • [...] – The (un)documented Frame Metadata Tag. Thanks to Keith Peters’ bit-101 for background info. I’ve created a great demo that is simple to [...]

  • panel says:

    thanks Keith for solution. I have been using it for a long time. Juten Tach suggested different aproach witch BTW is also working with FDT.
    I made complete summing up on this matter.
    http://www.actionscript.org/forums/showthread.php3?p=1076780#post1076780

  • [...] 可以看这篇文章:http://www.bit-101.com/blog/?p=946。 [...]

  • Matthieu says:

    Bonjour,

    Pour les développeurs francophone, j’ai réalisé un tutoriel vidéo avec un exemple en français à partir de cet article sur bit-101 : http://www.actionscript-facile.com/preloader-as3/article128553.html

    For french developers, i made a tutorial with the source code.

    Bye,

  • [...] fois, sur le site bit-101, j’ai trouvé une option de compilation très [...]

  • Lonfor says:

    Кино онлайн http://kinodoma.net/ смотреть бесплатно.

  • vvzoltan says:

    To anyone having the Variable not defined problem: make sure you go to the second frame BEFORE attempting to instantiate your main class (after your application has loaded). Use an EnterFrame listener, or and addFrameScript command, whatever you want.

    I did it like this: addFrameScript(1, initApp) in the factoryClass constructor, and once my preloader dispatched the Loaded event, I just did a nextFrame(); The initApp method is where I used getDefinitionByName to instantiate the Main class.

    Cheers!

  • [...] 今天看到一个比较老的文章,就是将这个的http://www.bit-101.com/blog /?p=946    介绍的很全面很细致,但是结果试下来却没有成功。 [...]

  • Nils says:

    Thanks! This was still the best resource I found for getting a preloader to work, even after all these years. The “nextFrame()” part is vital, but doesn’t get mentioned much elsewhere.

  • Sven says:

    Thanks…that’s exactly what I needed to get into this. Now I can start figuring out, how this preloader exactly does what it does ;)

    Big thx here!

  • [...] Keith Peters posted a really detailed write-up of how to use this tag for preloading a few months ago. Basically, the deal is that you can use this tag to force the compiler to create a two-frame SWF file. ActionScript: [...]