The Custom ImageLoader Class

The ImageLoader class loads concurrently any number of external images (jpg, gif, or png). As you can see from the code below, the loading of external files is done by using instances of the Loader class. See our tutorial 3D Menu, Bitmap Fills and Loading External Images in Flash CS3 for a discussion of the Loader class. Each image is assigned its own instance of the Loader class, say 'loader'. Each 'loader' fires the built-in AS3 events 'Event.COMPLETE' when loading concludes successfully, or the event 'IOErrorEvent.IO_ERROR' if loading could not be completed. (For reasons other than Flash Player security violations; we do not address the security errors in this tutorial). The problem we face is that with images loading simultaneously, we have no way of predicting which image will be loaded last. Thus, we have no way of catching the moment when all images have loaded succesfully. For that we need to create a custom event. We do that in the ImageLoader class. Actually, we create two custom events within the class: one is dispatched when all images finished loading, the other is dispatched if an error occurres with any of the images.

Creating custom events in ActionScript 3 is simple. All we need to do is to extend the EventDispatcher class contained in the package flash.events.*. Any subclass of the EventDispatcher is capable of dispatching custom events. Thus, our ImageLoader is a subclass of the EventDispatcher. (It is worth noting that many familiar classes, e.g. the Sprite, the MovieClip classes and other display objects are all subclasses of the EventDispatcher and thus are capable of dispatching custom events.)

To create a custom event in a class that extends the EventDispatcher, we need to give our event a name and then use the 'dispatchEvent' method of the EventDispatcher. The general syntax in any subclass, say 'YourClass', of the EventDispatcher for doing that looks as follows:

 

public static const SOMETHING_HAPPENED:String="somethingHappened";

 

//When the required conditions are satisfied call the dispatchEvent method:

 

dispatchEvent(new Event(YourClass.SOMETHING_HAPPENED));

 

Then, when you use an instance of YourClass, say instOfYourClass, you listen to the custom event as follows:

 

instOfYourClass.addEventListener(YourClass.SOMETHING_HAPPENED, itHappened);

 

function itHappened(e:Event):void {

 

...................

 

}

 

We will listen to the custom events defined in ImageLoader in the FlipImage class where we will create an instance of ImageLoader.

Below is the code in ImageLoader class. To keep the flow intact, we put our comments as comments within the code.

 

package {

import flash.display.*;

import flash.events.*;

import flash.net.URLRequest;

/*
We are extending the EventDispatcher class contained in the flash.events package. Any instance of a subclass of EventDispatcher is capable of dispatching custom events. Many of AS3 built-in classes are subclasses of the EventDispatcher class, for example, the Sprite class and other diplay object classes.
*/

public class ImageLoader extends EventDispatcher {

/*
We are defining constants corresponding to our two custom events. Similarly as for built-in events, later, when we add listeners to instances of ImageLoader, we can refer to the events by the names of the constants, e.g. ImageLoader.IMGS_LOADED, or by their string value e.g. 'imgsLoaded'.
*/

public static const IMGS_LOADED:String = "imgsLoaded";

public static const LOAD_ERROR:String = "loadError";

private var loadersArray:Array;

private var numImgs:int;

private var numLoaded:int;

private var isError:Boolean;

/*
_bitmapsArray is the array that will be populated by bitmaps corresponding to the loaded images once the 'loadImgs' method runs. We declare it as a private property but we will make it into a read-only property later in the script by defining a getter for it without defining a setter. loadCanRun variable will make sure that two calls to 'loadImgs' method do not overlap.
*/

private var _bitmapsArray:Array;

private var loadCanRun:Boolean;

 

public function ImageLoader(){

 

//The constructor of the class initializes 'loadCanRun'.

//It is the method 'loadImgs' below that performs all the main tasks.

 

this.loadCanRun=true;

 

}

/*
'loadImgs' method takes an array of strings as a parameter. For the method to function properly, the strings should represent addresses of the image files to be loaded. The method listenes for IO loading errors. (For example, the server is too busy and the file appears non-existent.) The method does not listen to FlashPlayer security errors. We assume that the image files are at locations that do not violate the security settings of the swf file that uses ImageLoader.
*/

public function loadImgs(imgsFiles:Array):void {

 

//If the method is called more than once, it will perform its duties

//only after the previous call concluded successfully.

 

if(loadCanRun){

 

loadCanRun=false;

 

//The counter variable counting how many images have been loaded.

 

numLoaded=0;

 

//The variable that remembers the current error status.

 

isError=false;

 

//The number of images to be loaded.

 

numImgs=imgsFiles.length;

 

//The array of bitmaps, each representing a loaded image.

 

_bitmapsArray=[];

/*
For each image file, we will use a separate instance of the Loader class. That is because we will be loading images simultaneously rather than consecutively. Consecutive loading is easier to code but it causes visible delays. In the loop that follows, we populate the array of Loaders and attach listeners to each Loader. One listens to an image finishing loading, the other to an occurrance of a loading error. Then we evoke the 'load' method for each Loader with the address of the corresponding image.
*/

loadersArray=[];

 

for(var i:int=0;i<numImgs;i++){

 

loadersArray[i]=new Loader();

loadersArray[i].contentLoaderInfo.addEventListener(Event.COMPLETE, imgLoaded);

loadersArray[i].contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorOccured);

loadersArray[i].load(new URLRequest(imgsFiles[i]));

 

}

 

}

 

}

 

private function imgLoaded(e:Event):void {

 

//When any of the images finishes loading, the count is increased by 1

//and the function 'chackLoadStatus' is called. The function checks if all the images

//have been loaded succesfully.

 

numLoaded+=1;

checkLoadStatus();

 

}

/*
If a loading error occurs with any of the images, the function 'errorOccured' runs. The function dispatches one of our custom events: ImageLoader.LOAD_ERROR. Note the syntax when dispatching a custom event.
*/

private function errorOccured(e:IOErrorEvent):void {

 

isError=true;

dispatchEvent(new Event(ImageLoader.LOAD_ERROR));

 

}

/*
'checkLoadStatus' function runs each time an image is completely loaded. If the number of images loaded is equal to the total number of images to be loaded, the function dispatches the custom event: ImageLoader.ALL_LOADED. Then the function removes all the listeners and clears Loaders which we no longer need as the images has been stored by the function in _bitmapsArray.
*/

private function checkLoadStatus():void {

 

var i:int;

 

if(numLoaded==numImgs && isError==false){

 

for(i=0;i<numImgs;i++){

 

_bitmapsArray[i]=Bitmap(loadersArray[i].content);

 

}

 

 

for(i=0;i<numImgs;i++){

 

loadersArray[i].contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, errorOccured);

loadersArray[i].contentLoaderInfo.removeEventListener(Event.COMPLETE, imgLoaded);

loadersArray[i]=null;

 

}

 

loadersArray=[];

loadCanRun=true;

dispatchEvent(new Event(ImageLoader.IMGS_LOADED));

 

}

 

}

 

/*
In order for 'bitmapsArray' to act as a public, read-only property, we define the getter method without defining the setter.
*/

public function get bitmapsArray():Array {

return _bitmapsArray;

}

}

}

 

The ImageLoader class has two public static constants. 'static' means the contants are the same for every instance of the class. The constants correspond to the two custom events:

  • IMGS_LOADED:String = "imgsLoaded"
  • LOAD_ERROR:String = "loadError"

The ImageLoader class has one public, read-only property:

  • bitmapsArray   This is the array of bitmaps corresponding to loaded images. The array is populated after the method 'loadImgs' has run and images have loaded without an error.

The ImageLoader class has the following public methods (besides the constructor discussed above):

  • loadImgs(imgsFiles:Array):void   The method takes an array of strings as a parameter. The strings represent URLs of the image files to be loaded. Once called, the event listeners set by the method trigger LOAD_ERROR event in case of an error. Otherwise, they trigger IMGS_LOADED event when all the images are loaded. When the event IMGS_LOADED is dispatched, the public, read-only property bitmapArray is populated with bitmap objects corresponding to loaded images. 'loadImgs' method can be called again on the same instance of ImageLoader but only after the previous call to the method concluded successfully. (If called before IMGS_LOADED event is dispatched for the prior call, the method does nothing.)

Download

  • Download all 'fla', 'as', and 'jpg' files corresponding to this tutorial: spin_take2.zip

Note:   More complex custom events can be created by extending the AS3 Event class and having a subclass of the EventDispatcher class dispatch such custom events. Instead of the generic: 'dispatchEvent(new Event(customEventType));' one would use then
'dispatchEvent(instanceOfACustomEventSubclass);'. Extending the Event class is a bit more complicated. It is a subject for a separate (upcoming) tutorial.

On the next page, we discuss the FlipImage class. The class creates an instance of ImageLoader. After all the images have loaded, the class provides the spinning functionality.

Back to Bridging the Gap Tutorials              Back to Flash and Math Home

The site www.flashandmath.com is maintained by Doug Ensley (doug@flashandmath.com) and Barbara Kaskosz (barbara@flashandmath.com).
It has been developed with partial funding from the National Science Foundation and the Mathematical Association of America.