views:

354

answers:

2

I'm trying to load a bunch (about 100) of images into memory, so I can display them at various times. Originally I had simply embedded them, but that of course resulted in the swf file being larger than I wanted. So now I'm trying to change it to load them in the background because they aren't needed immediately.

There are probably plenty of problems with this. The current on is that I'm getting an error that says 'TypeError: Error #1034: Type Coercion failed: cannot convert "foo.jpg" to Class.'

I've been googling this awhile, assuming loading an external image is a common thing. That's where I got the Loader and URLRequest code, but I'm clearly missing something. Maybe it's due to my goofy looping logic.

Here's the class so far

public class CardImages2
    {
     public static var fooImage1:Class;
     public static var fooImage2:Class;
     public static var fooImage3:Class;
     public static var fooImage4:Class;

     private static var curImgClass:Class;

     public static function load():void {
      // map of cards and their urls
      var dict:Dictionary = new Dictionary;
      dict[fooImage1] = "fooImage1.jpg";
      dict[fooImage2] = "fooImage2.jpg";
      dict[fooImage3] = "fooImage3.jpg";
      dict[fooImage4] = "fooImage4.jpg";

      var url:String;
      var loader:Loader = new Loader();
      var urlReq:URLRequest;

      for each(var key:Class in dict) {
       url = String(dict[key]);
       curImgClass = key;
       loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadListener); 
       urlReq = new URLRequest(encodeURI(url));
       loader.load(urlReq);
      }
     }

     private static function loadListener(e:Event):void {
      curImgClass.source = Class(e.currentTarget.content);
     }
    }
A: 

You should give bulk-loader a try. I've used it on a couple of projects and it works rather well. Just make sure to clean up after it, because it can be a memory hog, and could cause a partiularly nasty leak if you're loading in 100 images.

Alex Jillard
+1  A: 

There might be a few things going on here, depending on what it is you're trying to accomplish.

While it's possible to load bitmap data and create Class objects from it for later use, it's more common to load the bitmap data and just store the bitmaps, since it's unlikely you'll want to create multiple instances of the bitmap data once you load it, for lots of reasons, not the least of which is memory overhead.

Alex's suggestion of using BulkLoader is a fine one, but for purposes of illustrating one way to solve the problem yourself, I've thrown together this example, which loads three images as Bitmap instances into a Dictionary object:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onCreationComplete()">

    <mx:Script>
     <![CDATA[

      private var loaders:Dictionary;
      private var images:Dictionary;

      private var imageUrls:Array = ["Image1.png", "Image2.png", "Image3.png"];

      private function onCreationComplete():void
      {
       loadImages();
      }

      private function loadImages():void
      {
       loaders = new Dictionary();
       images = new Dictionary();

       for each (var imageUrl:String in imageUrls)
       {
        var urlLoader:URLLoader = new URLLoader();
        urlLoader.addEventListener(Event.COMPLETE, onURLLoaderComplete);
        urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
        urlLoader.load(new URLRequest(imageUrl));

        loaders[urlLoader] = imageUrl;
       }
      }

      private function onURLLoaderComplete(event:Event):void
      {     
       var loader:Loader = new Loader();
       loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
       loader.loadBytes(event.target.data);

       loaders[loader.contentLoaderInfo] = loaders[event.target];
       delete loaders[event.target];
      }

      private function onLoaderComplete(event:Event):void
      {
       images[loaders[event.target]] = event.target.content;
       delete loaders[event.target];
      }

     ]]>
    </mx:Script>

    <!-- These won't bind, but should illustrate how to access the bitmaps -->
    <mx:Image source="{images['Image1.png']}" />
    <mx:Image source="{images['Image2.png']}" />
    <mx:Image source="{images['Image3.png']}" />

</mx:Application>

This is a good bit of code, but the steps are pretty straightforward:

  1. Load each image with its own URLLoader, using a Dictionary object to remember which loader went with each image;
  2. When each URLLoader returns with a result, use a Loader to capture the actual bytes of the result; and
  3. Store the bytes of the Loader-loaded result in your images Dictionary.

Once the loading's all complete, you should have a usable Dictionary, keyed by your image URLs (or filenames, or whatever you like), containing each individual image instance. From there, if you need to create Class objects (e.g., for use as custom cursors, etc.), you can -- post back if that's what you're trying to do, and we'll pick it up from there.

Christian Nunciato
Thanks very much, this is fantastic!! I'm still sorting through fully understanding how it works and why everything is done, but I got the basics working. Now I just have to figure out how I want to key the images and get them back to the objects they belong to.
What is the typeof the event.target.content? I did typeof and only got object. I had issues when I tried to use the resulting content as the source of > 1 image. When I tried to use it as the source of the 2nd image, the first one disappeared. The usage was using the original image as a thumbnail, then on mouseover displaying a large on on another Image. I read a little about Bitmap and Image, and then tried to cast these results into a Bitmap, which didn't work. Eventually, I just set the source of my Images to the url, and I guess it loads it then. It also works for > 1 image this way also.
This followup probably deserves its own question, what are the differences between Images and Bitmaps and BitmapData. Also, what is the difference between loading the image via Loader and simply setting the Image.source as the url.