views:

1925

answers:

3

In a Flash game I am developing, there are some settings that are set by an external XML file. When I run the SWF file through the Flash IDE, it loads fine. If I run the same file as a projector (.exe) or the independent SWF file, it does not load the XML file.

My (unexpected) fix was to assign an error event listener to the loader object. When I published the file again, the XML loaded properly in the projector and standalone SWF files. (I have since verified that commenting out the error event handler restores the bug).

Here's the block of code involved (with extraneous code and function calls removed):

public function getSettings():void {
outputBox = getChildByName("output_box") as TextField;
var xmlLoader:URLLoader = new URLLoader();
var xmlData:XML = new XML();    
xmlLoader.addEventListener(Event.COMPLETE, loadXML, false, 0, true); 
xmlLoader.addEventListener(ErrorEvent.ERROR, function (e:Error) 
 { outputBox.appendText(e.message) });

try {    
 xmlLoader.load(xmlPath);
} 
catch(err:Error) {
 trace(err.message);
 outputBox.appendText(err.message);
 checkChances("0");
}

function loadXML(e:Event):void {

 try {
  xmlData = new XML(e.target.data);
  var chances:String = xmlData.chances.text();
  var dbURL:String = xmlData.database.text();

  trace("Chances are set to: " + chances);     
  trace("Database URL is set to: " + dbURL);
  outputBox.appendText("Chances are set to: " + chances);
 }
 catch(err:Error) {    
  outputBox.appendText(err.message);
 }
  checkChances(chances);
  dbPath = new URLRequest(dbURL);
}

}

Let me know if you have run into this, or if you can shed some light on what may be happening. Thanks!

EDIT:

Here is the code which does not work. (I also edited the code that does work to show all the other bits that I took out, just in case they might be effecting it):

public function getSettings():void {
outputBox = getChildByName("output_box") as TextField;
var xmlLoader:URLLoader = new URLLoader();
var xmlData:XML = new XML();    
xmlLoader.addEventListener(Event.COMPLETE, loadXML, false, 0, true); 
/*xmlLoader.addEventListener(ErrorEvent.ERROR, function (e:Error) 
 { outputBox.appendText(e.message) });*/

try {    
 xmlLoader.load(xmlPath);
} 
catch(err:Error) {
 trace(err.message);
 outputBox.appendText(err.message);
 checkChances("0");
}

function loadXML(e:Event):void {

 try {
  xmlData = new XML(e.target.data);
  var chances:String = xmlData.chances.text();
  var dbURL:String = xmlData.database.text();

  trace("Chances are set to: " + chances);     
  trace("Database URL is set to: " + dbURL);
  outputBox.appendText("Chances are set to: " + chances);
 }
 catch(err:Error) {    
  outputBox.appendText(err.message);
 }
  checkChances(chances);
  dbPath = new URLRequest(dbURL);
}

}

A: 

The answer to your question is no, actionscript 3.0 does not require an error event handler for XML. It does not even require a complete handler! That's the point of .addEventListener(), the event listeners are optional.

Sounds to me like there is more going on with your code then you present here.
(You commit out the error event listener, and then everything works o.k., that makes no sense at all!)

Are you executing the files from the same location at all times? That is my guess as to why the XML would not load, maybe you moved your .swf file to another folder?

ForYourOwnGood
Yes, I am always executing the files from a local networked drive. Moving the files to my desktop and testing there has the same results.
A: 

This is just a wild guess, but isn't it possible that in the earlier version of the program, the load() command was issued before addEventListener(), and that you reordered them (to the correct order) when you added the second, error listener? If so, then it is definitely a timing issue. It would be helpful if you also included the code which does not work.

UPDATE

I think Herms is right. When you add a single, locally scoped listener as a weak reference, not only the listener itself, but also the URLLoader object gets garbage collected (since without listeners, it does not make sense to keep it) before the download completes. (Why this happens in standalone mode and not in the Flash IDE is probably by chance, depending on exactly how GC works.) When you add a second, strong reference error event listener, tada, no more GCing.

So,either try what Herms suggests: use a wider scope function as a completion listener, or simply drop the weak reference argument from the addEventListener() call.

David Hanak
No, I've always had the event listener before the load command. I have posted the code which does not work.
Fair enough. But then, its probably just me, but you say "My (unexpected) fix was to assign an event listener to the loader object." and the error event listener is listed in the code. And still, this is the one that does not work. Then what was the unexpected fix again?
David Hanak
I apologize--I meant to say that "My (unexpected) fix was to assign an *error* event listener to the loader object."
Herms was correct. Thank you for your help and your elaboration on Herms's answer.
+1  A: 

On the first addEventListener you're telling it to use weak references (that last argument to the call). Your loadXML function is defined within your getSettings() method. Once you leave the getSettings() scope loadXML goes out of scope. The only thing left referencing loadXML is the event listener, but since you tell it to use a weak reference that will not prevent it from being garbage collected. So, by the time the event is raised the loadXML method is probably garbage collected.

My guess is that when you define the other listener the anonymous method defined there keeps the getSettings() scope around (as it's part of that method's scope), which will keep loadXML() in scope.

What you really should do is refactor your loadXML method into an actual member function on your object, not an anonymous method defined in getSettings(). That will keep things cleaner, and would prevent the garbage collection you're seeing, as the method would stay in scope as long as the object does.

If for some reason you don't want to make loadXML a member function then removing the weak reference flag should be enough to fix it. However, you may end up with a bit of a memory leak due to the way those anonymous method work.

Herms
You were absolutely correct--I still wanted the garbage collection, so I changed loadXML() into a member function and removed the error event listener, and it works perfectly. I appreciate your help and clear explanation.