12 Replies Latest reply: Sep 18, 2012 3:27 AM by bla124356 RSS

    Dual EventListener problem

    bla124356

      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[i].@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

        • 1. Re: Dual EventListener problem
          Andrei1 Community Member

          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[i].@f);
                  var loader:Loader = new Loader();
                  var request:URLRequest = new URLRequest(images.node[i].@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[i].@f);
                  loader = new Loader();
                  loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);
                  loader.load(new URLRequest(images.node[i].@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);
          }
          
          • 2. Re: Dual EventListener problem
            bla124356 Community Member

            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[i].@f); is to display the current file being loaded into the array.

             

            I will give this a shot and report back!

            • 3. Re: Dual EventListener problem
              Andrei1 Community Member

              In you original code there is no Event type specified when you add event listener in xmlReady() function.

              • 4. Re: Dual EventListener problem
                bla124356 Community Member

                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[i].@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?

                • 5. Re: Dual EventListener problem
                  Andrei1 Community Member

                  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[i].@f);

                          var loader:Loader = new Loader();

                          loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageReady);

                          loader.load(new URLRequest(images.node[i].@f));

                      }

                  }

                  • 6. Re: Dual EventListener problem
                    bla124356 Community Member

                    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?

                    • 7. Re: Dual EventListener problem
                      Andrei1 Community Member

                      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++)

                      • 8. Re: Dual EventListener problem
                        Andrei1 Community Member

                        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));
                            }
                        }
                        
                        • 9. Re: Dual EventListener problem
                          dmeN Community Member

                          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

                          }

                          • 10. Re: Dual EventListener problem
                            bla124356 Community Member

                            Thanks! I seem to have looked over that one!

                            • 11. Re: Dual EventListener problem
                              bla124356 Community Member

                              Thanks! I'll keep that in mind!

                              • 12. Re: Dual EventListener problem
                                bla124356 Community Member

                                Well the XML object should provide the same functionality (i tested it and it does) but, perhaps this is good practice. Thanks!