A Flash Developer Resource Site

Results 1 to 8 of 8

Thread: URLLoader - No Error Event, No Success Event

  1. #1
    Senior Member
    Join Date
    Jan 2006
    Posts
    133

    Question URLLoader - No Error Event, No Success Event

    All,

    I have encountered an interesting problem when I try to load an .xml file using a URLLoader (within my own custom class). I have several configuration .xml files which I use to configure the application when it launches.

    For example, in the code below, myCustomLoader is a custom class I wrote that takes an .xml file as a parameter. The myCustomLoader class encapsulates all the instantiation of the URLLoader class and error handling etc. The code below operates as expected, the configuration files load into memory, and they're accessible throughout my App.

    Actionscript Code:
    // On launch
    var Config1:XML = new myCustomLoader("Config1.xml");
    var Config2:XML = new myCustomLoader("Config2.xml");
    var Config3:XML = new myCustomLoader("Config3.xml");

    I've developed a situation where I need to load some "2nd level" .xml files. For example, a .xml file full of images for a gallery display.
    However, as the user interacts with the app and objects are added and removed and the state of the application changes, sometimes these "2nd level" .xml files load successfully, and sometimes they don't load or fail at all.
    By that I mean I LITERALLY get no notification or hint from Flash about what is wrong. There is no compile or runtime error, but there is no "complete" event either. The App doesn't stop working, the .xml just doesn't load. In fact, it seems that .xml doesn't even open.

    In myCustomLoader I have listeners for EVERY event that the URLLoader dispatches, with trace statements that would tell me what was wrong. For example:
    Actionscript Code:
    // From some other class
    var anotherXML:XML = new myCustomLoader("2ndlevel1.xml");

    // myCustomLoader class
    package {
       
        public class myCustomLoader extends EventDispatcher {
                   
            public function myCustomLoader(filePath:String) {
               
                var urlLoader:URLLoader = new URLLoader("2ndlevel1.xml");

                urlLoader.addEventListener(Event.OPEN, onOpen, false, 0, true);
                urlLoader.addEventListener(ProgressEvent.PROGRESS, onProgress, false, 0, true);
                urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus, false, 0, true);
                urlLoader.addEventListener(Event.COMPLETE, onComplete, false, 0, true);
                urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError, false, 0, true);
                urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError, false, 0, true);

                // Try loading the text
                try {
                    urlLoader.load(new URLRequest(filePath));
                } catch (errLoad:Error) {
                    trace("Unable to load content : " + errLoad.message);
                }
            }
           
            // ...
            // trace errors or success, etc.
            // return an XML object
        }
    }
    The load() in the "try" block successfully executes, but the "open" event never triggers. I'm assuming the problem lies in the application state and code outside of the loader class since it seems to work fine in other situations.
    Unfortunately, I'm working with someone else's "legacy" code, so I have no idea where the problem could be, so I wouldn't even know what code to post here and ask for proof-reading.

    So, I'm hopping someone might be able to give me a "code-agnostic" reason why a URLLoader.load() call would not fail, but no events would dispatch and no data would be loaded?

    Thanks!

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    You are using weak references, and your urlLoader is a function-local variable. That means that it is eligible for garbage collection as soon as the function (the constructor) finishes. If garbage collection happens between then and the time the event would fire, it'll simply be lost.

    Why are you using weak references in the first place?

  3. #3
    Senior Member
    Join Date
    Jan 2006
    Posts
    133
    oops, that was a typo, it is a class variable:

    Actionscript Code:
    // myCustomLoader class
    package {
       
        public class myCustomLoader extends EventDispatcher {

            private var urlLoader:URLLoader = new URLLoader();
           
            public function myCustomLoader(filePath:String) {
               
                urlLoader.addEventListener(Event.OPEN, onOpen, false, 0, true);
                urlLoader.addEventListener(ProgressEvent.PROGRESS, onProgress, false, 0, true);
                urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus, false, 0, true);
                urlLoader.addEventListener(Event.COMPLETE, onComplete, false, 0, true);
                urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError, false, 0, true);
                urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError, false, 0, true);

                // Try loading the text
                try {
                    urlLoader.load(new URLRequest(filePath));
                } catch (errLoad:Error) {
                    trace("Unable to load content : " + errLoad.message);
                }
            }
           
            // ...
            // trace errors or success, etc.
            // return an XML object
        }
    }


    Quote Originally Posted by 5TonsOfFlax View Post
    Why are you using weak references in the first place?
    Well, weak references have always worked for me in the past, I realize some believe it counts as "sloppy" coding. I'll try getting rid of the weak references, but considering the corrections above, I'll be surprised if that has an effect since urlLoader is a class variable?

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Okay, well now I'm confused about how you are "returning" an XML object from the constructor of myCustomLoader. Please actually copy and paste myCustomLoader in its entirety, because this makes no sense.
    Code:
    var Config1:XML = new myCustomLoader("Config1.xml");
    That cannot work, because myCustomLoader is not an instance of XML.

  5. #5
    Senior Member
    Join Date
    Jan 2006
    Posts
    133
    Quote Originally Posted by 5TonsOfFlax View Post
    not work, because myCustomLoader is not an instance of XML.
    Wow, I'm really off today...
    I'm sorry, thanks for taking the time, by the way:
    Actionscript Code:
    // On launch
    var Config1:myCustomLoader = new myCustomLoader("Config1.xml");
    var Config2:myCustomLoader = new myCustomLoader("Config2.xml");
    var Config3:myCustomLoader = new myCustomLoader("Config3.xml");

    // myCustomLoader class
    package {
       
        public class myCustomLoader extends EventDispatcher {

            private var urlLoader:URLLoader = new URLLoader();
           
            public function myCustomLoader(filePath:String) {
               
                urlLoader.addEventListener(Event.OPEN, onOpen, false);
                urlLoader.addEventListener(ProgressEvent.PROGRESS, onProgress, false);
                urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus, false);
                urlLoader.addEventListener(Event.COMPLETE, onComplete, false);
                urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError, false);
                urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError, false);

                // Try loading the text
                try {
                    urlLoader.load(new URLRequest(filePath));
                } catch (errLoad:Error) {
                    trace("Unable to load content : " + errLoad.message);
                }
            }
           
            // ...
            // trace errors or success, etc.
        // ...
        // various methods to do E4X stuff with the loaded XML data.
        }
    }

    Anyway, so I tried ditching the weak references, and it actually did have an effect.

    I guess I'm a little confused as to why the weak references would allow the urlLoader to be garbage collected. Perhaps I didn't understand fully how weak references work?

    So, if an object is only referenced by weak listeners, it IS eligible to be garbage collected at any time, correct?

    So in the code below, urlLoader could get collected at any time, even BEFORE the onComplete() method triggered? (Which would explain some of the problems I was seeing).
    Actionscript Code:
    // myCustomLoader Class
    package {
       
        public class myCustomLoader extends EventDispatcher {
           
            private var urlLoader:URLLoader = new URLLoader();
           
            public function myCustomLoader(filePath:String){
                urlLoader.addEventListener(Event.COMPLETE, onComplete, false, 0, true);
                urlLoader.load(new URLRequest(filePath));
            }
           
            private function onComplete(e:Event):void{
                trace("XML file has loaded!");
                urlLoader.removeEventListener(Event.COMPLETE, onComplete, false);
                dispatchEvent(e);
            }
        }
    }

    However, if I don't use weak listeners, then the urlLoader should persist until I remove the listener in the onComplete() function, at which point the urlLoader would be ELIGIBLE, but not necessarily removed?
    Actionscript Code:
    // myCustomLoader Class
    package {
       
        public class myCustomLoader extends EventDispatcher {
           
            private var urlLoader:URLLoader = new URLLoader();
           
            public function myCustomLoader(filePath:String){
                urlLoader.addEventListener(Event.COMPLETE, onComplete);
                urlLoader.load(new URLRequest(filePath));
            }
           
            private function onComplete(e:Event):void{
                trace("XML file has loaded!");
                urlLoader.removeEventListener(Event.COMPLETE, onComplete, false);
                // urlLoader can now be collected?
                dispatchEvent(e);
            }
        }
    }

    However, even with weak listeners, if I happen to create other references to the urlLoader, then the urlLoader will be INELIGIBLE until those other references are destroyed?
    Actionscript Code:
    // myCustomLoader Class
    package {
       
        public class myCustomLoader extends EventDispatcher {
           
            private var urlLoader:URLLoader = new URLLoader();
            private var Some_array:Array = [];
           
           
            public function myCustomLoader(filePath:String){
                Some_array.push(urlLoader); // urlLoader persists in memory until Some_array[0] is deleted?
                urlLoader.addEventListener(Event.COMPLETE, onComplete, false, 0, true);
                urlLoader.load(new URLRequest(filePath));
            }
           
            private function onComplete(e:Event):void{
                trace("XML file has loaded!");
                urlLoader.removeEventListener(Event.COMPLETE, onComplete, false);
                dispatchEvent(e);
            }
        }
    }

  6. #6
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Actually, once you've moved the urlLoader variable to a class instance level, that reference will prevent the urlLoader from being garbage collected as long as the enclosing myCustomLoader is around. Now, if the myCustomLoader were to have no references to it, it could be garbage collected and take its urlLoader with it.

    When you are creating your myCustomLoaders, are you keeping references to them, or are you creating them as local variables inside a function?

  7. #7
    Senior Member
    Join Date
    Jan 2006
    Posts
    133
    Quote Originally Posted by 5TonsOfFlax View Post
    When you are creating your myCustomLoaders, are you keeping references to them, or are you creating them as local variables inside a function?
    Well, unfortunately I'm trying to sift through somone else's code... but GENERALLY... for the "top-level" instances (Config1, etc.) are created in a global space. Then, my "2nd level" xmls are usually loaded by other classes. But, I usually have a reference to the myCustomLoader at the class level. For example, the classes that need to load 2nd level .xml files generally have the format of:
    Actionscript Code:
    // any class that needs to load a .xml
    package {

        public class otherClass extends MovieClip {
           
            private var myDataSource:myCustomLoader;
                   
            public function otherClass(){
            }
           
            public function init(filePath:String):void{
                // myDataSource.addEventListener(Event.COMPLETE, onComplete) // Doesn't work here because myDataSource is null.
                myDataSource = new myCustomLoader(filePath);
                myDataSource.addEventListener(Event.COMPLETE, onComplete);
            }
           
            private function onComplete(e:Event):void{
                // Do something
            }
        }
    }

    I removed the weak references from the event listener.
    Is it possible that the load is actually completing so fast, that it finishes before I explicitly add the listener?

  8. #8
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Yes it is possible that the load completes very fast if the resource was in the browser cache. But you should at least still get the trace from myCustomLoader since that class adds its listeners before it does the load.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center