I don't even know how to explain this behavior but I'll try. I am loading images from an external url that requires basic auth so I am using URLLoader to load the image from a unique ID. The ID gets passed to the itemrenderer which then proceeds to load the image. But the images switch around on their own when I scroll. If I load more than 7 images or so it starts repeating images....
Youtube video of error: http://www.youtube.com/watch?v=ZYoqlS14gWQ
Relevant code:
<s:ItemRenderer name="RandomItemRenderer" creationComplete="init();"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="false">
<s:states>
<s:State name="normal" />
<s:State name="hovered" />
<s:State name="selected" />
</s:states>
<fx:Script>
<![CDATA[
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import flash.net.URLRequestMethod;
import mx.utils.ObjectProxy;
import customclasses.Settings;
[Bindable] private var coverArtImage:Image;
private var myCoverArtLoader:URLLoader;
[Bindable] private var coverArtSource:String;
private function init():void {
get_coverArt();
}
private function get_coverArt(): void {
if (!data.coverArt) {
set_nullCoverArt();
} else {
var requestString:String = "/rest/getCoverArt.view?v=1.5.0&c=AirSub&id=" + data.coverArt;
var requestURL:String = Settings.ServerURL + requestString;
myCoverArtLoader = new URLLoader();
var myRequest:URLRequest = new URLRequest();
var authHeader:URLRequestHeader = new URLRequestHeader();
authHeader.name = 'Authorization';
authHeader.value = 'Basic ' + Settings.EncryptedCreds();
myRequest.requestHeaders.push(authHeader);
myRequest.url = requestURL;
myRequest.method = URLRequestMethod.GET;
myCoverArtLoader.dataFormat = URLLoaderDataFormat.BINARY;
myCoverArtLoader.addEventListener(Event.COMPLETE, set_coverArt);
myCoverArtLoader.addEventListener(IOErrorEvent.IO_ERROR, set_failedCoverArt);
myCoverArtLoader.load(myRequest);
}
}
private function set_coverArt(evt:Event) : void {
coverArtImage = new Image();
coverArtImage.source = myCoverArtLoader.data;
myCoverArtLoader.removeEventListener(Event.COMPLETE, set_coverArt);
}
private function set_nullCoverArt() : void {
coverArtImage = new Image();
coverArtImage.source = "assets/nullCoverArt.jpg";
}
private function set_failedCoverArt() : void {
coverArtImage = new Image();
coverArtImage.source = "assets/nullCoverArt.jpg";
myCoverArtLoader.addEventListener(IOErrorEvent.IO_ERROR, set_nullCoverArt);
}
]]>
</fx:Script>
<s:Image source.normal="assets/coverOutline.png" source.selected="assets/coverOutlineYellow.png" source.hovered="assets/coverOutlineYellow.png"
height="226" width="226" />
<s:VGroup top="4.5" bottom="5" width="200" horizontalAlign="center" letterSpacing="10"
paddingBottom="5" paddingTop="9" verticalAlign="middle" x="13.5">
<s:Image id="ui_imgCoverArt" width="200" height="200" source="{coverArtImage.source}"/>
<s:Label text="{data.title}" width="160" styleName="RandomList" />
</s:VGroup>
ItemRenderers are reusable and cached, i.e. there are only limited count created in List to fill its area (rowCount +- couple). And when you scroll, new renderers are not instantiated, instead the one renderer that was scrolled out goes up or down and is filled with new data.
That's why you can not rely on
creationComplete
event, it will be fired only once for each instance of renderer.The solution is to override
data
setter and build there the behaviour needed:Useful link: How flex itemRenderer works ? (their life cycle)