Tuesday, 25 November 2008

AS3 - Careful with Loader.load()

On a recently finished project for Wunderman - All New Ford Fiesta - I made an odd discovery about Flash Player 9's inbuild flash.display.Loader class.

The Fiesta site's flagship feature is a customisable Flickr feed that is pushed through an algorithm to form the shape of the car. This feed updates based upon your likes and dislikes of particular content, it's all pretty cool, but that's another post. This meant plenty of loading pain with many a thumbnail - there is a queue that streams in around 400 images to initially populate the car. Now, as this was quite a load bandwidth-wise, this had to be done whilst the user was interacting, to keep the interest alive; this proved to be a whole world of hell. Essentially, what I found was, rapidly loading content using Loader.load() has a surprisingly large processing expense. Extremely high, in fact. So much so that once we got to around the 70-80 image mark, the application ground to a halt.



Queue several long weeks of frustration. Queue several weeks of staring at other Flickr sites that worked twice as fast. In HTML. How is this possible? Well, I can't tell you that, but what I can give you is the following solution; and it's lightning quick:

[as3]
package aspectvision.core
{
import flash.display.Loader;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.utils.ByteArray;

public class ByteLoader extends Loader
{
protected var urlLoader : URLLoader;
protected var context : LoaderContext;

public function ByteLoader()
{
super();
}

override public function load( request : URLRequest, context : LoaderContext = null ) : void
{
this.context = context;

urlLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener( Event.OPEN, dispatchEvent );
urlLoader.addEventListener( SecurityErrorEvent.SECURITY_ERROR, dispatchEvent );
urlLoader.addEventListener( IOErrorEvent.IO_ERROR, dispatchEvent );
urlLoader.addEventListener( ProgressEvent.PROGRESS, dispatchEvent );
urlLoader.addEventListener( Event.COMPLETE, onComplete );
urlLoader.load( request );
}

protected function onComplete( event : Event ):void
{
var bytes : ByteArray = urlLoader.data as ByteArray;
contentLoaderInfo.addEventListener( Event.INIT, onInit );
loadBytes( bytes, context );

dispatchEvent( event );
}

protected function onInit( event : Event ) : void
{
dispatchEvent( event );
}
}
}
[/as3]

The above example uses a binary URLLoader.load() to load the image as a byte array. Once this has loaded, it uses the Loader.loadBytes() method to render the data. Don't ask me why this is quicker, it just is. Exceedingly so. I hope this saves someone a lot of head-scratching and affords them the 3 or 4 weeks I lost which could have been better spent polishing.

No comments:

Post a Comment