In this post I’d like to talk about other things you can do to make your projects run better, be less buggy, and use less memory.
The format of your class, if it’s a MovieClip, a Sprite, a .swf file you are loading into another swf, or any type of display object that’s interactive, should look like below:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class MyLoadedMovieClip extends MovieClip {
// class variables here
public function MyLoadedMovieClip()
{
// variables created in the constructor
addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
}
private function init(e:Event):void
{
//
}
public function dispose():void
{
// stop Timers
// remove event listeners
// remove *some* class variables
}
}
The dispose function is used to help mark items in the class for garbage collection. Things that should be marked for garbage collection include anything that’s going to keep the flash player working hard for no reason. This includes:
If you don’t need any of these things, you should get rid of it. That’s what the dispose function does.
Example usage:
// create an instance
var item:MyLoadedMovieClip = new MyLoadedMovieClip();
// add it to the stage
addChild(item);
// to dispose, remove it from the stage
removeChild(item);
// call the dispose function
item.dispose();
// null the reference
item = null
So…aside from stopping your timers and removing event listeners, which is straightforward, here are some finer points about what to remove in your dispose() function.
A class variable is any variable declared before you constructor function.
For example:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class MyLoadedMovieClip extends MovieClip {
public var my_graphic_that_is_on_stage:Star = new Star;
private var my_graphic:PacMan;
private var my_other_graphic:PacMan;
private var A:String;
private var B:Number;
private var C:Vector.;
private var something_you_need_before_object_is_on_stage:String;
public function MyLoadedMovieClip()
{
All that stuff in bold are class variables. Most of these you should clear out in your “dispose” or “destroy” function (more on that later). I say “most” because there are a few of these variables that’s actually been created before this class has even hit the stage, and these ones should not be in your dispose() function.
Instances become public variables in your class. Because this variable was already on the stage of object (not the root stage or the “stage” stage) before the the constructor function, you shouldn’t put it in your dispose() or destroy function.
Likewise, any class variable that you instantiate (I mean by using the new keyword) in your constructor function should also not be in your dispose or destroy method.
public function MyLoadedMovieClip() { something_you_need_before_object_is_on_stage = "really important"; addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true); }
So, that class variable,
something_you_need_before_object_is_on_stage
should really not be in your dispose function.
This is because when it comes to stuff like Sprites and MovieClips, these kind of objects are often reused – added to the stage and removed from the stage.
If you remove that object from the stage, and then call it’s dispose function, those needed variables will be gone and it will cause you a major headache.
Anything that you’ve put in your init() function (when your object arrives on the “stage” stage)…dispose!
As another note…the init() (short for “initalize”) function is a good best practice function. Your constructor should be as small as you can make it (or better yet, empty).
I like to make my init() function get called when my object is added to the stage:
addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
Variables that are display objects (such as Sprites or MovieClips) should be removed from the stage and then made null.
removeChild(my_graphic);
removeChild(my_other_graphic);
my_graphic = null;
my_other_graphic = null;
Strings can be made null, and Numbers can be undefined (there’s probably a better way to clear numbers…if so let me know)
myString = null;
myNumber = undefined
Vectors or arrays can have their length trimmed to 0
MyVector.length = 0
Actually, this post isn’t really about using loadMovie with Actionscript 3, but about using the Actionscript 3.0 version of loadMovie, and using it with SWFAddress.
First your class variables:
private var isLoaded:String;
private var currentLoader:Loader;
private var isHome:Boolean = true; // home page is the first page
I use a variable called isLoaded to tell me what .swf or “section” of my site I’m am going to load. When there is something in “isLoaded” not only do I know what section (swf) I am loading, I also know that something has loaded and so this prevents me from accidentally loading the .swf twice.
Secondly – and this is even more important – I use one loader to load all of my movies (swfs). I use the same loader to load, and when I unload, I use unloadAndStop instead of unload().
If you use a different loader for each .swf, you will have problems because even though you uloaded the swf file, a reference for that file exists (i.e. the loader). If that reference exists, the .swf won’t be marked for garbage collection and your project will act buggy.
By using the same loader over and over, it’s a) easy to keep track of, and b) easy to clear out and reuse for other .swf files.
Next, my init() function:
private function init():void
{
SWFAddress.addEventListener(SWFAddressEvent.CHANGE,
changeAddress, false, 0, true);
}
When my Main swf (MovieClip) is on the stage, I listen for the SWFAddress event:
private function changeAddress(e:SWFAddressEvent):void
{
if (e.value != "/")
{
SWFAddress.setTitle("Your-home-page-title" + e.value.substring(1));
}
else
{
SWFAddress.setTitle("Your-home-page-title");
}
switch(e.value)
{
case "/what-you-want-your-link-to-be-called":
loadSWF("what-you-want-your-link-to-be-called", "my-swf.swf");
break;
case "/what-you-want-your-2nd-link-to-be-called":
loadSWF("what-you-want-your-2nd-link-to-be-called", "my-swf2.swf");
break;
}
}
e.value is the “address” of each .swf file. You can set this value by calling:
SWFAddress.setValue("what-you-want-your-link-to-be-called");
Whenever you call this method (setValue)…the address in your URL will change to, say:
http://www.my-project.com/index.php#/what-you-want-your-link-to-be-called
So, in my switch statement above, if a new address gets set, it calls a loadSWF function:
private function loadSWF(value:String, url:String):void
{
if (isLoaded == value) return;
isLoaded = value;
unloadCurrent();
currentLoader = new Loader();
currentLoader.load(new URLRequest(url));
currentLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,
startSWF, false, 0, true);
}
So, a few things here.
If there is already an address set and it’s the same address (isLoaded == value) then the function basically stops (by using return). This is just a little safeguard to stop me from loading the same .swf file twice.
if (isLoaded == value) return;
Next, if it’s a different value (i.e. a different .swf or /address) I set the isLoaded to the new value:
isLoaded = value;
After this, I make sure to unload any .swf that’s already been loaded:
unloadCurrent();
Following that is some pretty standard loader code to load the swf, followed by a function that actually adds the content of the loader to the stage once the loader has finished loading:
private function startSWF(e:Event):void
{
addChild(currentLoader.content);
}
Note: I added the loader.content, instead of the loader. While you can add the loader, the behaviour is unexpected – add the content of the loader instead.
Below is some code to load the movieclip and change the address:
myButtonMovieClip.addEventListener(MouseEvent.CLICK, onMouseClick, false, 0, true);
private function onMouseClick(e:MouseEvent):void
{
SWFAddress.setValue("what-you-want-your-link-to-be-called");
}
Below is a way to unloadAndStop. I found just using unloadAndStop() wasn’t enough – it’s better to remove the loader.content from the stage, then unloadAndStop, then null the loader.
private function unloadCurrent():void
{
if (isLoaded && currentLoader != null && this.contains(currentLoader.content))
{
removeChild(currentLoader.content);
currentLoader.unloadAndStop();
currentLoader = null;
isLoaded = null;
}
}
I also made a “Home” button to go back to my “home” or “main” swf
private function goHome(e:CustomEvent):void
{
if (!isHome)
{
SWFAddress.setValue("/");
unloadCurrent();
}
}