Copy link to clipboard
Copied
Hello All,
I am new to these forums, and to ActionScript. I have come here to ask the following question, as I cannot find answers elsewhere.
I have the following short piece of as3 script:
import flash.display.Bitmap;
import flash.display.Loader;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
var imageArray:Array = new Array();
var file:String = "xml/images.xml";
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(file);
loader.load(request);
loader.addEventListener(Event.COMPLETE, xmlReady);
function xmlReady(e:Event):void {
var xmlData = XML(e.target.data);
trace(xmlData);
loadImages(xmlData);
addEventListener(Event., traceArray);
}
function loadImages(images:XML):void {
for (var i:Number = 0; i < images.length(); i++){
var loader:Loader = new Loader();
var request:URLRequest = new URLRequest(images.node.@f); // load element f (filepath/filename.jpg) out of a node element
loader.load(request);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);
}
}
function imageReady(e:Event):void {
imageArray.push(e.target.content as Bitmap);
}
function traceArray():void{
trace(imageArray.length);
}
The script does not throw any exceptions or warnings. Somehow, the script will only load one image into array imageArray, in stead of all (5) images specified in the XML document. I am certain that the XML is correct, because the XML object can load it's data and display it (i tested this). I suspect this problem has something to do with the asynchronous execution due to COMPLETE events being used. Can anyone point me in the right direction as to how this script may be rewritten in a better (functional) way and/or tell me a way to do load assets in as3 without using events? Or is this the only way possible in as3 in order to prevent browser freezes?
With regards,
bla124356
Copy link to clipboard
Copied
1. What event are listening to in the line addEventListener(Event., traceArray);?
2. What do you see in traces:
function loadImages(images:XML):void
{
for (var i:Number = 0; i < images.length(); i++)
{
trace(images.node.@f);
var loader:Loader = new Loader();
var request:URLRequest = new URLRequest(images.node.@f); // load element f (filepath/filename.jpg) out of a node element
loader.load(request);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);
}
}
3. All listeners MUST BE ADDED BEFORE load is called. In local environments it is so fast that load may be complete before Flash hears the event listener to which is added.
So you code should be something like this
import flash.display.Bitmap;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
var imageArray:Array = new Array();
var file:String = "xml/images.xml";
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(file);
loader.addEventListener(Event.COMPLETE, xmlReady);
loader.load(request);
function xmlReady(e:Event):void
{
var xmlData = XML(e.target.data);
trace(xmlData);
addEventListener(Event.ENTER_FRAME, traceArray);
loadImages(xmlData);
}
function loadImages(images:XML):void
{
var loader:Loader;
for (var i:int = 0; i < images.length(); i++)
{
trace(images.node.@f);
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);
loader.load(new URLRequest(images.node.@f));
}
}
function imageReady(e:Event):void
{
imageArray.push(e.target.content as Bitmap);
LoaderInfo(e.target).removeEventListener(Event.COMPLETE, imageReady);
}
function traceArray():void
{
trace(imageArray.length);
}
Copy link to clipboard
Copied
Ahh that explains a lot, thanks! Well my final trace(imageArray.length); in the traceArray eventlistener is to check if in the end, my array contains any elements. But it doesn't return anything, which is why I am here The trace(images.node.@f); is to display the current file being loaded into the array.
I will give this a shot and report back!
Copy link to clipboard
Copied
In you original code there is no Event type specified when you add event listener in xmlReady() function.
Copy link to clipboard
Copied
I have changed the source to:
import flash.display.Bitmap;
import flash.display.Loader;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
var imageArray:Array = new Array();
var file:String = "xml/images.xml";
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(file);
loader.addEventListener(Event.COMPLETE, xmlReady);
loader.load(request);
function xmlReady(e:Event):void {
var xmlData = XML(e.target.data);
trace(xmlData);
loadImages(xmlData);
}
function loadImages(images:XML):void {
for (var i:Number = 0; i < images.length(); i++){
var loader:Loader = new Loader();
var request:URLRequest = new URLRequest(images.node.@f);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);
loader.load(request);
}
}
function imageReady(e:Event):void {
imageArray.push(e.target.content as Bitmap);
trace(imageArray.length);
}
Now, I have come to suspect that the for loop does not play nice with events. I will research whether a solution in which each eventhandler loading an image from xml handles iteration using a global instead of using a for loop and see if that works.
P.S. how put my source in a nice code box here on the forums?
Copy link to clipboard
Copied
What do you see in traces output in this funcion?
function loadImages(images:XML):void
{
for (var i:int = 0; i < images.length(); i++)
{
trace(images.node.@f);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);
loader.load(new URLRequest(images.node.@f));
}
}
Copy link to clipboard
Copied
I did not see the trace in that function.
I have changed my code to:
import flash.display.Bitmap;
import flash.display.Loader;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
var imageArray:Array = new Array();
var file:String = "xml/images.xml";
var arrayLength:Number = 0;
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(file);
loader.addEventListener(Event.COMPLETE, xmlReady);
loader.load(request);
function xmlReady(e:Event):void {
var xmlData = XML(e.target.data);
trace(xmlData);
trace(xmlData.node.length);
trace(xmlData.length);
arrayLength = xmlData.node.length;
loadImages(xmlData);
}
function loadImages(images:XML):void {
while (arrayLength > 0){
var loader:Loader = new Loader();
var request:URLRequest = new URLRequest(images.node[arrayLength].@f);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);
loader.load(request);
}
}
function imageReady(e:Event):void {
imageArray.push(e.target.content as Bitmap);
arrayLength--;
trace(imageArray.length);
}
And here is the output:
<root>
<node id="1" f="images/1.jpg" th="images/thumbs/1.jpg" t="image 1"/>
<node id="2" f="images/2.jpg" th="images/thumbs/2.jpg" t="image 2"/>
<node id="3" f="images/3.jpg" th="images/thumbs/3.jpg" t="image 3"/>
<node id="4" f="images/4.jpg" th="images/thumbs/4.jpg" t="image 4"/>
<node id="5" f="images/5.jpg" th="images/thumbs/5.jpg" t="image 5"/>
</root>
Now, it seems that for some weird reason, the xmlData in the xmlReady event handler is having a fit of quantum weirdness. As you can see, trace(xmlData); works and output's it's xml. However, trace(xmlData.node.length); and trace(xmlData.length); do not work. Any ideas?
Copy link to clipboard
Copied
You don't read nodes properly.
Loop must be:
for (var i:int = 0; i < images.node.length(); i++)
not
for (var i:int = 0; i < images.length(); i++)
Copy link to clipboard
Copied
Thanks! I seem to have looked over that one!
Copy link to clipboard
Copied
You don't have to use for loop. Use for...each loop - it is faster:
function loadImages(images:XML):void
{
var loader:Loader;
for each (var node:XML in images.node)
{
trace(node.@f);
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);
loader.load(new URLRequest(node.@f));
}
}
Copy link to clipboard
Copied
Thanks! I'll keep that in mind!
Copy link to clipboard
Copied
I think it should be mentioned you could've, and probably should've, been using an XMLList object - it is what has the length() method and makes iterating chunks of XML easy.
So, in your xmlReady function:
function xmlReady(e:Event):void {
var xmlData:XML = new XML(e.target.data);
trace(xmlData);
var nodeList:XMLList = xmlData.node;
trace(nodeList.length()); //5
trace(nodeList[0].@f); //images/1.jpg
}
Copy link to clipboard
Copied
Well the XML object should provide the same functionality (i tested it and it does) but, perhaps this is good practice. Thanks!