views:

2032

answers:

5

My question is very simple: In flex3, is there a way to load an xml file synchronously?

I know how to load asynchronously, using a load event. This may be useful, or may not. I just want to read the file, parse it, do what I have to do with it, and continue executing code.

I have a component that uses an xml file to store some configuration parameters. I need to read the file when the object is initialized. However, with the event model, I can't control when the file is loaded, so I must write code to "wait" for the code to load. This is just ridiculous, or is it me? I want code like this:

var foo:Foo = new Foo(); //This constructor should read the xml and initialize the object.
foo.doSomething(); //When I call this method the xml must be already handled.

I can handle the xml file on the event, and it works fine, but the event fires after the doSomething method.

I hope I have explained myself. I think this should be really easy, but it's driving me crazy. I don't want to write code to wait for the event unless it's really necessary. I feel all this should be just one line of code!

+1  A: 

i think, there is an "after" event with load.

so you have to split the call to the new() and the call to the do() in two distinct methods, so the new() is called in initalisation and do() is calld after loading()

pseudosyntax:

beforeInitialisation()
  disableDoSomething()
  new()...
  loader.addEvent(AFTERLOAD, afterLoad)


afterLoad()
  enableDoSomething()


someMethod()
  doSomething()
Peter Miehle
Sorry I don't understand. Inside the Foo class, I can split code in different events. The problem is I cannot control when the events fire. foo.doSomething() should be called after all these events, and I dont know how to make that happen.
Rafa G. Argente
the "var foo:Foo = new Foo();"-part and the "foo.doSomething();"-part have to be in two different functions/methods (in SQL it would be a BEFORE and and AFTER-trigger)
Peter Miehle
Thanks peter, it is clearer now. However, this doesnt suit my needs either, sorry. I cannot afford to call somemethod and just dont do anything. See my own answer
Rafa G. Argente
have you seen my change "enableDoSomething()". If so, the question rouses: who triggers the "doSomething()"? is it the the "afterLoad()" or is it a "userAction()"? if the later, use the enable-part
Peter Miehle
A: 

Call foo.doSomething(); from inside an event handler for the XML loading event (e.g. EVENT.Complete or somesuch depending on how exactly you are loading the file). That is the recommended way to go.

dirkgently
Yes, but it would be a mess. doSomething is not part of the initialization conceptually. It will be called many times during the lifecycle of the object. Right now I can call it right after init if it's absolutely necessary. However there's no good reason to do it apart from this.
Rafa G. Argente
The `many times` must have a precursor. Try to identify that and create and event and set doSomething() as the handler.
dirkgently
Yes, that's the case. The user clicks a button, that fires the event. Right now the object was lazily created the first time the user clicks. I'll initiliaze it when loading the application. See my new answer. Thanks for your help!
Rafa G. Argente
so do not allow the user to fire the button, until the object is loaded
Peter Miehle
This answer does not address how to solve this problem SYNCHRONOUSLY. It is very easy to handle this asynchronously, but sometimes that's just horribly messy, and we need a way to handle a simple synchronous download.
Joshua
+1  A: 

I will answer myself, however I'd still like to know if someone comes up with better ideas. Answers from dirkgently and Peter Miehle are both helpful but does not solve my actual problem.

It seems synchronous loading is just not possible. The loading could fail or take too long, and we can't afford to freeze the application just because of that. That's reasonable, however I still feel it can make code more complicated than it should.

What I'm going to do is loading the xml file before creating the object, and passing it as a parameter to the constructor. That way I'll make sure the object has the xml file loaded when it's needed. This however is also not an ideal solution, because now I have to make another class responsible for the "private things" of Foo.

Any better ideas?

Rafa G. Argente
'Freezing the app' -- that is the exact reason why blocked i/o is not allowed.
dirkgently
AIR however does have a FileStream object with an option to work in synchronous mode.
dirkgently
Are you loading the file from network? If not, then the wait shouldn't really be that long. Otherwise, if it's a huge file, try using Socket/XMLSocket and read in chunks.
dirkgently
+1  A: 

It's not possible to load synchronously, flash is built for the web and you can never be sure how long a call takes. Air is different because that loads from the filesystem, and there are nowhere near the same amounts of delay there.

The cleanest solution would be to listen for the load to complete inside Foo and calling doSomething() from inside, this way your "outer" class won't need to bother at all.

If you do absolutely need to call foo.doSomething() from the outside, you can use the event system. Let your Foo class dispatch an event when it is done loading:

dispatchEvent(new Event(Event.COMPLETE, true));

To catch that you will need to listen for it like so:

foo.addEventListener(Event.COMPLETE, handleFooComplete);

And you event handler function should look like this:

private function handleFooComplete(e:Event):void{
    foo.doSomething();
}

However you choose to do it, you will need to listen for Event.COMPLETE on the loader. There's no getting around that.

grapefrukt
A: 

Old question but I bet a lot of people still come here so, here's my solution.

Create a custom event that you dispatch inside of the function that handles the resultEvent

Have the object you want to do something, i think in this case it was foo, to listen for this custom event which then would call doSomething().

Ryan