I wanted to write this post for a very long time but Lee Brimelow beat me to it. But that is alright because he confirmed that the way I was doing my preloaders was a good one.
In AS2 we were used to seeing preloaders in the 2 first frames of a flash movie, but that technique didn’t work well when you used Classes and Library object exported for ActionScript. Even in AS2, I started making my preloader external. An external preloader is a swf that sole purpose is to load another swf.
I suggest you watch Lee’s video because it explains very well why you should use an external preloader and how to do it.
I think his method can be perfected to be even more memory and CPU efficient.
Let’s take a look at the code he uses:
var l:Loader = new Loader(); l.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loop); l.contentLoaderInfo.addEventListener(Event.COMPLETE, done); l.load(new URLRequest("content.swf")); function loop(e:ProgressEvent):void { var perc:Number = e.bytesLoaded / e.bytesTotal; percent.text = Math.ceil(perc*100).toString(); } function done(e:Event):void { removeChild(percent); // was removeChildAt(0) but it make more sense this way percent = null; addChild(l); }
That’s pretty simple and straight forward. Lee makes sure to remove assets he used for is preloader to free memory, which is good, but if you really wanted to push things a bit farther here is what you would do:
var myMovie:Sprite; var l:Loader = new Loader(); l.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loop, false, 0, true); l.contentLoaderInfo.addEventListener(Event.COMPLETE, done, false, 0, true); l.load(new URLRequest("content.swf")); function loop(e:ProgressEvent):void { var perc:Number = e.bytesLoaded / e.bytesTotal; percent.text = Math.ceil(perc*100).toString(); } function done(e:Event):void { removeChild(percent); // was removeChildAt(0) but it make more sense this way percent = null; myMovie = Sprite(l.content); addChild(myMovie); l.contentLoaderInfo.removeEventListener( ProgressEvent.PROGRESS, loop); l.contentLoaderInfo.removeEventListener(Event.COMPLETE, done); l = null; }
First difference you might find is that I set the weakReference of the listeners to true. It doesn’t serve any purpose in this case but I think it is a good practice and a good habit to always put weakReference to true for you listeners.
The second thing you might see is that I don’t add the Loader to the stage. I don’t want to do that because I want to get rid of the Loader. It did it’s job, now I don’t want it using memory for nothing. So instead I created a Sprite called myMovie and I give it the content of the Loader. For this to work, the content of the Loader as to be a Sprite, but you can always change the type of myMovie to adapt to what you are loading. Once I gave myMovie the content I add it to the stage.
Now that the Loader handed off its package I can get rid of it. The first step to do so is to remove the listeners. Listeners take up CPU resources and in this case they will never be used again so I might as well remove them. Once this is done I set the Loader to null to ged rid of it. I could have just done that and not remove the listeners before because I used weakReferences and the GarbageCollector would have destroyed them, but why wait until then when you can do it now.
Well that was it, it is really just a little cleaner but I think that if someone was looking to push this further that’s how he would do this.
Do you know any better way of preloading?



#1 by Theo - September 19th, 2008 at 03:20
One interesting aspect of using a separate SWF for preloading is that it completely removes what little possibility there was that Google would index your Flash site, at least until they start indexing dynamically loaded content.
I’m not saying you shouldn’t use this preloading/bootstrapping technique, on the contrary, I think it’s great. What I am saying is that Google’s new Flash indexer is completely useless, because it doesn’t take in consideration the way Flash developers actually create Flash content. This is an example of that.
#2 by funkyboy - September 19th, 2008 at 04:40
To help garbage collection even more, I’d move up removeListener() to line 16.
#3 by doug - September 19th, 2008 at 06:06
Nice idea but shouldn’t you change this:
l.removeEventListener( ProgressEvent.PROGRESS, loop);
l.removeEventListener(Event.COMPLETE, done);
to
l.contentLoaderInfo.removeEventListener( ProgressEvent.PROGRESS, loop);
l.contentLoaderInfo.removeEventListener(Event.COMPLETE, done);
#4 by doug - September 19th, 2008 at 06:08
Here’s my example:
package com.deceptiveresolution.kohive.swf.preloading
{
import flash.text.TextField;
import flash.events.ProgressEvent;
import flash.events.Event;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.MovieClip;
import flash.display.Sprite;
public class PreloadingContainer extends MovieClip
{
private var __container:Sprite;
private var __preloader:Loader;
public var percent_txt:TextField;
private static const __APP_URL:String = “TextChat.swf”;
public function PreloadingContainer()
{
trace(“\nPreloadingContainer()”);
__preloader = new Loader();
__preloader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, _onPreloadProgress, false, 0, true);
__preloader.contentLoaderInfo.addEventListener(Event.INIT, _onPreloadInit, false, 0, true);
__preloader.contentLoaderInfo.addEventListener(Event.COMPLETE, _onPreloadComplete, false, 0, true);
__preloader.load(new URLRequest(__APP_URL));
}
private function _onPreloadProgress(e:ProgressEvent):void
{
trace(“\nPreloadingContainer._onPreloadProgress()”);
var percentage:Number = e.bytesLoaded / e.bytesTotal;
percent_txt.text = String(Math.ceil(percentage * 100));
}
private function _onPreloadInit(e:Event):void
{
trace(“\nPreloadingContainer._onPreloadInit()”);
percent_txt.text = “100″;
}
private function _onPreloadComplete(e:Event):void
{
trace(“\nPreloadingContainer._onPreloadComplete()”);
removeChild(percent_txt);
percent_txt = null;
__container = Sprite(__preloader.content);
addChild(__container);
__preloader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, _onPreloadProgress);
__preloader.contentLoaderInfo.removeEventListener(Event.INIT, _onPreloadInit);
__preloader.contentLoaderInfo.removeEventListener(Event.COMPLETE, _onPreloadComplete);
__preloader = null;
}
}
}
#5 by doug - September 19th, 2008 at 06:10
@Theo
Another good point but we could just have a load of static text in our preloading swf describing our site with perhaps links to more detailed external assets… just an idea for now.
#6 by zedia.net - September 19th, 2008 at 09:21
@Theo
You are totally right, but as you say I don’t think it is of any use to try to make your SWF searchable for Google. Progressive enhancement is still the way to go.
#7 by zedia.net - September 19th, 2008 at 09:27
@Doug
Thx for pointing out my error on the remove listener. It is fixed now.
#8 by barry - September 23rd, 2008 at 03:53
HI,
I’ve read a lot of articles that suggest you should set use weak reference to true. Is there any instance when you might want it to be false?
#9 by zedia.net - September 23rd, 2008 at 13:06
@barry
The only case where you would want weak reference set to false on a listener is when the only thing that keeps the object, that the listener is on, from being Garbage Collected is the listener itself. And I don’t see any application of this so I always set the weak reference to true.
#10 by Tunde - October 8th, 2008 at 22:23
please go to 8landphoto.com, click on work and you should see my problem is there a step by step way to fix this?
#11 by panorama360 - October 23rd, 2008 at 13:25
very usefull, it saved me a lot of time! thanx
#12 by Garfty - October 29th, 2008 at 08:22
It’s nice to see this, and it’s the way i’ve been doing it after reading various articles etc etc…
My only question is how would you do a nice dynamic loader, one that fades in, does the load, then fades out to reveal the content. There is a big spaceship version which is nice, however I feel this is quite complex still.
Cheers for the post, cleared a couple of niggly things up for me
^_^
#13 by Sharpy - November 10th, 2008 at 22:32
This works well BUT … content.swf starts playing BEFORE event.COMPLETE fires! So by the time your progress hits 100%, your main file content is many frames into the animation.
Any ideas how to stop/pause the content.swf until its fully loaded?
#14 by zedia.net - November 12th, 2008 at 15:38
@sharpy
Put a stop on the first frame of the movie that is being loaded and in the onComplete function of your preloader start the content. Using the code I have written up there it should look something like this:
myMovie = MovieClip(l.content);
addChild(myMovie);
myMovie.play();
In my exemple the loaded content was a Sprite but you would have to change it to MovieClip to make your thing work.
#15 by John Smith - November 22nd, 2008 at 08:28
I took this concept and added to it. I am building a thumb panel, so I wanted all of my thumbnail urls to be held externally in an XML file. Basically what this does is loads a series of .jpgs of .swfs and increments the x coordinate of the dynamic text field everytime i changes. Here is my code. I am just learning how to garbage collect, so I would appreciate if you would look at my code and critique it.
var xml:XML;
var xmlPath:String = “./Gallery1/gallery.xml”;
var imagelist:XMLList;
var numberOfImages:int;
var thumbUrl:String;
var thumbx:Number=0;
var i:Number=0;
var ihaschanged:Boolean = false;
var thmbLoader:Loader = new Loader();
var loader = new URLLoader();
loader.load(new URLRequest(xmlPath));
loader.addEventListener(Event.COMPLETE, xmlLoaded);
//create a dynamic preloader text field
var preloaderText = new TextField();
preloaderText.name = ‘textfield’;
preloaderText.selectable = false;
preloaderText.x = 27;
preloaderText.y = 20;
preloaderText.width = 30;
var txtFormat:TextFormat = new TextFormat();
txtFormat.color = 0×000000;
txtFormat.size = 12;
preloaderText.setTextFormat(txtFormat);
addChild(preloaderText);
function xmlLoaded(e:Event):void {
xml = new XML(e.target.data);
imagelist = xml.gallery.image;
numberOfImages = imagelist.length();
createThumbnail();
}
function createThumbnail():void{
if(i
#16 by John Smith - November 22nd, 2008 at 08:30
looks like the bottom half got cutt off so here is the rest of it…
function createThumbnail():void{
if(i
#17 by Fernando - December 16th, 2008 at 03:17
I used this method before, but the problem is that it doesn’t work in ie 6 or 7 and google chrome too, I don’t know why. I search in google but I can’t find nothing about this bug. I’m using the flash player v.10, any one have an idea?
#18 by Beebs - February 18th, 2009 at 19:12
I am using this preloader as external document class in the movie (let’s say website.swf) to load external movie (let’s say main.swf). The main.swf is all constructed with external document classes.
I always got Error #1009: Cannot access a property or method of a null object reference.
Any suggestion?
#19 by Beebs - February 20th, 2009 at 07:11
Hi It’s me again.
I manage to deal with my post#18 above.
However, the further issue arrive : I load more than 2 external movie into var myMovie.
Although I keep the “l = null” , the movie are sit on top each other instead of replacing them.
Can you shed me alight how to unload the old one and load the new one?
Thanks a lot
#20 by zedia.net - February 20th, 2009 at 10:34
You have to remove your previous content from the display list before you set it to null. The addChild method create a link to the object so as long as you didn’t remove that link, that object cannot be destroyed(garbage collected).
#21 by Beebs - February 28th, 2009 at 05:22
Thanks for your reply.
I have further wish list. Since I love your approach of this preloader, how possible to have them in a document class?
The reason I have this wish list is that I will use the preloader in many places ( like child movies) – so it will be handy if I can call it in a function – something like this.
Thanks Zedia
#22 by Bill - March 30th, 2009 at 09:09
I find the little pop-out thing(“annoying” reply – quote) blocks the text when trying to read what people posted .
#23 by Deon - August 30th, 2009 at 23:57
I did everything exactly as written in the original post, and it works fine offline, but once it is on my server the text starts at 100, and with a trace of “Math.ceil(perc*100).toString()” I see it looping the percent count over and over. This seems to be the case with every preloader I try to use, any suggestions?
#24 by Deon - September 6th, 2009 at 15:10
I wanted to leave an answer in case someone stumbled in here with my problem.
“Gzip compression is on in the server; turn it off it will be ok. Do so by using a .htaccess file and in it write this without qoutes ” Options +FollowSymLinks
RewriteEngine on
RewriteRule \.swf$ – [E=no-gzip:1] “
#25 by mark mun - October 14th, 2009 at 21:34
What do you do if your loaded swf also has external assets that it needs to load that needs to be displayed in the loader swf progress bar?
#26 by DeltaFrog - February 19th, 2010 at 22:23
If your loading the swf into the other swf does the browser know too look for newly updated swf’s with this method? In as2 I always had to add a random id number too loaded swf’s. Any thoughts on that?
#27 by DeltaFrog - February 20th, 2010 at 01:18
I got a “Cannot access a property or method of a null object reference” error when I used this method to load my working swf. You do have to worry about how you code your file. For me it was not plug and play… ;(
#28 by DeltaFrog - February 20th, 2010 at 03:02
Ok sry for my rants up there, long day. ;D Everything seems to be working now.
Any suggestions on getting these two line to run with a delay?
myMovie=Sprite(l.content);
addChild(myMovie);
I tried Set interval but it didn’t work for me. Thanks in advance.
#29 by Karl - April 21st, 2010 at 11:09
Hey Guys,
Any way we could get the content to load into a container movieclip (called ‘container’ on main timeline) as at the moment the content.swf is loading over everything in the main.swf..
Here is my code
//Loading Default Section
var Xpos:Number = 0;
var Ypos:Number = 0;
var swf:MovieClip;
var myMovie:Sprite;
var loader:Loader = new Loader();
loader.x = Xpos
loader.y = Ypos
addChild(loader);
////////////////////////////////////
//Preloader
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loop, false, 0, true);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, done, false, 0, true);
loader.load(new URLRequest(“swfs/section1.swf”));
function loop(e:ProgressEvent):void {
var perc:Number = e.bytesLoaded / e.bytesTotal;
percent.text = Math.ceil(perc*100).toString();
}
function done(e:Event):void {
removeChild(percent);
percent = null;
myMovie = Sprite(loader.content)
addChild(myMovie);
loader.contentLoaderInfo.removeEventListener( ProgressEvent.PROGRESS, loop);
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, done);
loader = null;
}
////////////////////////////////////
// Button Function
function btnClick(event:MouseEvent):void {
removeChild(loader);
var newSWFRequest:URLRequest = new URLRequest(“swfs/” + event.target.name + “.swf”);
loader.load(newSWFRequest);
loader.x = Xpos
loader.y = Ypos
addChild(loader);
}
////////////////////////////////////
// Button Listeners
section1.addEventListener(MouseEvent.CLICK, btnClick);
section2.addEventListener(MouseEvent.CLICK, btnClick);
section3.addEventListener(MouseEvent.CLICK, btnClick);
section4.addEventListener(MouseEvent.CLICK, btnClick);
////////////////////////////////////
any help would be appreciated.
Ta
#30 by husky - April 30th, 2010 at 13:11
I dont like AS3.. I personally think is powerful and whatever.. but its too complicated and.. complicatd things.. never last long.. cause newbies skip it cause its hard and they look for something easier.. so I say programming flash as3 will die… actually is dying.
#31 by zedia.net - April 30th, 2010 at 13:58
Haha, that is pretty funny, AS3 as been around for quite some time now, at least 3-4 years, and Flash hasn’t died yet. I hope you know that HTML5 will be just as hard; Javascript and ActionScript are quite similar. Anyway everyone is entitled to their beliefs.
#32 by Dan - June 1st, 2010 at 12:02
@doug
Could you write here clean way how to hand over flashvars to new loaded swf…
Thank you in advance
#33 by john - June 3rd, 2010 at 13:34
great!!!
i use this tutorial and it works nice
except when i put some code on the first
frame of the content.fla which gives me
this error.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at content_fla::MainTimeline/frame1()
why is this happening? any solution?
thank you!
#34 by Bernie - June 29th, 2010 at 17:10
For a solution to the #1009 Error see:
http://www.sitepoint.com/forums//showthread.php?t=642623