问题
I set a value to my xml object (xml = new XML(e.currentTarget.data);) during my event handler function (the function is executed after the event.COMPLETE) and if I trace the object inside my event function handler it shows my xml data.
but if I try to trace it outside the event handler function it doesn't show my xml content. Isn't there a way to get my xml object content value to show in an other function but not in the event handler function?
private var xml:XML;
public function XMLLoader(xmlURL:String)
{
var xmlURLRequest:URLRequest = new URLRequest(xmlURL);
var xmlURLLoader:URLLoader = new URLLoader(xmlURLRequest);
xmlURLLoader.addEventListener(Event.COMPLETE, xmlData);
}
private function xmlData(e:Event):void
{
e.currentTarget.removeEventListener(Event.COMPLETE, xmlData);
xml = new XML(e.currentTarget.data);
dispatchEvent(new Event(Event.COMPLETE));
trace(xml);
}
public function getXMLData():void
{
//I've find out that this shows null because this function is faster
//what do i do? put an event.complete in every following function?
trace(xml);
}
Thanks.
回答1:
I think you call getXMLData()
immediatelly after XMLLoader()
at that moment xml
object is still null. Try calling getXMLData()
inside xmlData()
function and you should see the difference.
回答2:
You are probably calling getXMLData() before your URLLoader completes however, in general, the code you are executing is in bad practice. Actionscript has no blocking whatsoever, so when you instantiate your new URLLoader with your URLRequest, it immediately begins the loading operation. If your file is cached, for example, your Event.COMPLETE listener may never fire as you are attaching it after you begin your loading operation.
I've attached below the ideal process for creating and loading data:
var data:XML;
var urlLoader:URLLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, urlLoader_completeHandler);
urlLoader.load(new URLRequest("path"));
private function urlLoader_completeHandler(event:Event):void
{
data = new XML(urlLoader.data);
}
If you want to apply this to your own XMLLoader class, I've included the "proper" implementation in AS3...however quite verbose.
import flash.net.URLLoader;
import flash.events.Event;
class XMLLoader extends URLLoader
{
public function XMLLoader()
{
super();
addEventListener(Event.COMPLETE, completeHandler);
}
private function completeHandler(event:Event):void
{
dispatchEvent(new XMLLoaderEvent(XMLLoaderEvent.COMPLETE, new XML(data)));
}
}
class XMLLoaderEvent extends Event
{
public static const COMPLETE:String = "xmlLoaderComplete";
public var data:XML;
public function XMLLoaderEvent(type:String, data:XML = null, bubbles:Boolean = false, cancelable:Boolean = false)
{
super(type, bubbles, cancelable);
this.data = data;
}
override public function clone():Event
{
return new XMLLoaderEvent(type, data, bubbles, cancelable);
}
}
To use the XMLLoader class:
var xmlLoader:XMLLoader = new XMLLoader();
xmlLoader.addEventListener(XMLLoaderEvent.COMPLETE, function(event:XMLLoaderEvent):void
{
trace(event.data);
});
xmlLoader.load(new URLRequest("data.xml"));
Best of luck!
回答3:
change your trace method to indicate if the xml is loaded yet...
you are running into a race condition
private var _xmlLoaded:Boolean=false;// add this to see if the xml is loaded
private function xmlData(e:Event):void
{
e.currentTarget.removeEventListener(Event.COMPLETE, xmlData);
xml = new XML(e.currentTarget.data);
_xmlLoaded=true;
dispatchEvent(new Event(Event.COMPLETE));
trace(xml);
}
public function getXMLData():void
{
if (_xmlLoaded)
trace(xml);
else
trace("not yet loaded");
}
回答4:
//NOTE: USE THIS IF YOU WANT TO ACCESS DIRECTLY TO THE FUNCTIONS OF THIS "CLASS" WITHOUT USING ANY EVENT LISTENER ON THE CLASS CAUSE IT ALREADY HAS ITS EVENT LISTENER ON EACH FUNCTION (THIS CAUSE ONE FUNCTION ONLY getXMLData())
private var xml:XML;
public function XMLLoader(xmlURL:String) {
var xmlURLRequest:URLRequest = new URLRequest(xmlURL);
var xmlURLLoader:URLLoader = new URLLoader(xmlURLRequest);
xmlURLLoader.addEventListener(Event.COMPLETE, xmlData);
}
private function xmlData(e:Event):void {
e.currentTarget.removeEventListener(Event.COMPLETE, xmlData);
xml = new XML(e.currentTarget.data);
dispatchEvent(new Event(Event.COMPLETE));
trace("1");//this used to come second of getXMLData() but it's solved now
trace(xml);
}
public function getXMLData():void {
//This function was coming first so if you don't want to use an event listener outside
//this class to wait for event.complete you can use it here to wait for it and access
//the function directly without being afraid of the object being null:
addEventListener(Event.COMPLETE, go)
function go(e:Event){
trace("2"); //now it ONLY comes AFTER the event.complete, no need for external listeners over this class. declare the class object and use getXMLData() directly cause it always comes second the event handler xmlData() :)
trace(xml);
}
}
来源:https://stackoverflow.com/questions/8378027/actionscript-3-how-to-keep-the-value-from-an-event-after-removing-that-event