R – how to load several external images; getting cannot convert to Class

actionscript-3apache-flex

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);
        }
    }

Best Answer

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.

Related Topic