Flash AS3 Do nothing until loaded - actionscript-3

I have this program, that needs to load a text file, which it can do, but since everything is multi-threaded on AS3, it continues with the program even though its not loaded. Like, if I was to make a function that loads the text, and then have it return the loaded text, it will always return "undefined". I have to add an event listener for when it's done, but the way I have to handle the returning of the text is awkward. Is there any way to make the program just wait, or do nothing until it's loaded?

It sounds like what you're looking for is for the data to load synchronously so that you can just make the loading call and have it return right away, like so:
# (this actually is not actionscript)
fileDataContents = open("file.txt", "r");
then have the fileDataContents immediately available to use.
By design this is not how flash works.
Loading external data in flash is not multithreaded, but rather asynchronous. One very good reason why synchronous loading is not done is that it causes blocking/locking of the program during the operation potentially resulting in a poor user experience.
Take for example, if this is loading a file over the web: what if the user's internet connection had just cut out/hiccupped or had been moved/deleted/modified suddenly on the server? Or what if the file is moderately sized but the user was on dial-up?
This is out of your control in most cases and the resulting behaviour may be that it causes flash to "forever" freeze in the user's browser window as it tries to load, possibly taking down the whole browser with it, ultimately ending in a poor user experience. By blocking/locking the program in that loop you would have no way to recover or respond to the user appropriately.

No, you can't.
Listening for the COMPLETE event like you have now is the correct way to wait and continue the application flow once done. I can't see how this would become awkward - I suggest updating your question to include information about what's making you uncomfortable about the event system so that I can help you from there.
Perhaps you're just not structuring your code in a way that works well with the event system. Here is how you can set up a very clean, straightforward way of loading some data and starting up the application once done.
Here's the document class, which can be used purely as a channel to load your text data which will be forwarded on to a fresh instance of the actual Application class:
public class Main extends Sprite
{
private var _application:Application;
private var _loader:URLLoader;
public function Main()
{
var fileUrl:URLRequest = new URLRequest("file.txt");
_loader = new URLLoader(fileUrl);
_loader.addEventListener(Event.COMPLETE, _textLoaded);
}
private function _textLoaded(e:Event):void
{
_loader.removeEventListener(Event.COMPLETE, _textLoaded);
// Load the main Application with the required text data.
_application = new Application( _loader.data );
}
}
And then your Application, which you can consider your central class.:
public class Application
{
public function Application(textData:String)
{
// Here we have access to the required text, and we can
// begin preparing the main Application.
trace(textData);
}
}

Related

How to call a remoteObject method that is outside of my TitleWindow component on Flex?

I have a TitleWindow component. It allows me to save some data provided through 3 TextInput.
That data "fills" a DropDownList which is in another TitleWindow component, not inside the original one.
How can I call the remoteObject method that fills (or refresh) my DropDownList?
Any ideas will be appreciated!
You can simply use a Singleton as a model if you'd like, this will allow you to share data, but beware keep data only that needs to be shared in here or it will just become a global nightmare.
Using a singleton means you'll have a class that you can only ever have one instance of. If you put properties in that class any time you reference it it will be the same memory throughout the application execution.
http://blog.pixelbreaker.com/actionscript-3-0/as30-better-singletons
Marking the singleton class or individual properties as Bindable will make it so you can watch for the changes and call a function.
http://livedocs.adobe.com/flex/3/html/help.html?content=databinding_8.html
Putting this together you have something like this:
[Singleton.as]
package
{
[Bindable]
public class Singleton
{
public var myListData:Array;
public static var instance:Singleton;
public static function getInstance():Singleton
{
if( instance == null ) instance = new Singleton( new SingletonEnforcer() );
return instance;
}
public function Singleton( pvt:SingletonEnforcer )
{
// init class
}
}
}
internal class SingletonEnforcer{}
Somewhere else you want to get a handle on this
[MyTitleWindow.as]
var instance:Singleton = Singleton.getInstance();
instance.myListData = [1,2,3];
[MyTitleWindowWithAList]
var instance:Singleton = Singleton.getInstance();
BindingUtils.bindSetter(funcUpdateList, instance, "myListData");
private function funcUpdateList(data:Object)
{
myList.dataProvider = data as Array;
}
Another option is to create an event that carries your data payload, dispatch that event from the first title window, and capture it, the problem with this is you have to register the listeners on the PopUpManager or SystemManager I believe because the TitleWindow's aren't direct children of the Application I believe.
Singletons are a bad idea and you should not get in the habit of using them. Instead, just dispatch an event from the View and catch it from something else that has access to your Service object.
Note that your Service should not be part and parcel of any View--the responsibility of a View is displaying data and capturing requests from the user to change the data, not communicating with a server.
For examples of an application written with this pattern in mind, check out
[Refactoring with Mate] (http://www.developria.com/2010/05/refactoring-with-mate.html) - The example has View source enabled
The same application done with RobotLegs - again, View Source is enabled.
Note that these are written against some popular frameworks, but they are written in such a way that you can easily replace that framework code with something else, even your own code.
For reference, here is the naiive implementation, where the service layer is being called directly in the Views. You couldn't call a different service without changing the Views, though the use of the static service means you could use it from elsewhere.
That static usage survived into the later examples, though today I would never write something depending on a globally accessible object. In part this is because I discovered Test Driven Development, and it is impossible to replace the "real" static object with an object that lets you isolate what you are testing. However, the fact that most of the code in the 2 "better" examples is insulated from that static object means that it is trivial to replace it with one that is provided some other way.
The lesson here is if you're going to use static, global objects, lock them away behind as much abstraction as you can. But avoid them if you're at all interested in best practice. Note that a Singleton is a static global object of the worst kind.

When should I load data in a Windows Phone 8 application?

I've seen a lot of questions here related to the OnNavigatedTo method, but none of them seem to answer the basic question of, "At what point should I load data?" The documentation on MSDN doesn't explicitly answer this question, as far as I can tell.
If I need to load a list of data from the local database, which method is the most appropriate to use? Should I use the OnNavigatedTo method, or the Loaded event?
What I've been using so far is this pattern, which seems to work well:
protected override void OnNavigatedTo(NavigationEventArgs e) {
base.OnNavigatedTo(e);
if (NavigationMode.New == e.NavigationMode) {
var data = LoadData();
this.DataContext = data;
}
}
What this means is that for a new instance of a page, load the data synchronously. This also means that the page will not be rendered until the data has finished loading and the profiler complains that I'm using too much UI thread time.
An alternate approach is this pattern:
protected override async void OnNavigatedTo(NavigationEventArgs e) {
base.OnNavigatedTo(e);
if (NavigationMode.New == e.NavigationMode) {
var data = await LoadData();
this.DataContext = data;
}
}
But with this pattern, it seems to me that navigation, and therefore page rendering may occur before I've loaded the data and set the DataContext, meaning unnecessary re-paints and what-not.
I usualy bind to a ViewModel directly in XAML. Then in OnNavigatedTo I trigger the view model to fetch its data async.
This allows me to show basic values from start (page title etc.). Then when I start fetching the data I can also activate a progressbar directly in the ViewModel and then remove it once the data is fetched.
I recommend you load your data asynchronously. OnNavigatedTo is one place where you can start the loading. If you're talking about a page that the user is almost certainly going to navigate to, then you may be able to start loading earlier.
I have a series of blog posts that look at how async has some friction with traditional OOP. There are a couple of posts that look at data binding in particular, e.g., asynchronous construction (the section on asynchronous initialization) and asynchronous properties (the section on data binding).
Just a few hours ago I announced the first stable release for my AsyncEx library, which includes the NotifyTaskCompletion types that you can use to kick off an asynchronous loading operation and have your view respond automatically (via data binding) when it completes.
But back to the core problem: you do have to show something while the data is loading. I recommend you do not consider this "unnecessary", but rather accept it as an opportunity to provide a better user experience. Think about what you want your app to look like on a slower phone or if there is an error loading the data. Any time there's I/O, design the "Loading..." and "Error" states as well as the "Loaded" state.

Loading an XML in ActionScript 3 before an event listener happens

I'm trying to fill some data from an xml feed we made into my Flash movie. The main action of this is in the constructor for MediaElementJS's .as file.
Anyway, the main problem is that I keep reading there is no way to load a URL synchronously in AS3 (which i still find hard to believe). This constructor calls both parse('url') and a function addEventListener(EVENT.ADDED_TO_STAGE, initializeAds);
Now the ads need info from the XML but the XML aint ready yet. I tried to call the ads at the end of the XML parser when I knew it would be prepped but it messes them up and the ad values never change from their defaults..
Oh wherefor art thou actionscript locking mechanism..
So is there anyway to preload data from a URL?
CODE:
public function LoadXML(e:Event):void
{
removeEventListener(Event.COMPLETE, LoadXML);
var xmlData:XML = new XML(e.target.data);
episodeData.pre.type = xmlData.episode.pre.ad.#type;
episodeData.pre.url = xmlData.episode.pre.ad.text();
episodeData.video = Number(xmlData.episode.video.#id); /*************** I CAN'T REMEMBER ***********/
episodeData.pageTitle = xmlData.episode.video.#pagetitle;
episodeData.title = xmlData.episode.video.#title;
episodeData.source = xmlData.episode.video.source.text();
episodeData.post.type=xmlData.episode.post.ad.#type;
episodeData.post.url=xmlData.episode.post.ad.text();
episodeData.nextEpisode=xmlData.episode.post.nextepisode.text(); //if not empty redirect to this
xmlLoading = false;
//THIS IS WHERE I TRIED TO CALL THE FUNCTION I NEED TO LOAD LATER
}
public function parse()
{
var xmlLoader:URLLoader = new URLLoader();
//var xmlData:XML = new XML();
xmlLoader.load(new URLRequest(rootURL + '/episode.aspx?associd=' + _episode));
//xmlLoader.addEventListener(Event.COMPLETE, processXML);
xmlLoader.addEventListener(Event.COMPLETE, LoadXML);
}
I've tried it with a static URL address and whatnot of course but no dice.
The code in the constructor works if I dynamically assign a static value but if I try chaining to events together to get the dynamic value and dynamic assignment it crunches.
In the constructor, definitely runs both by themselves:
parse();
// Google IMA EventListener
addEventListener(Event.ADDED_TO_STAGE, initialize);
Loading URLs is always asynchronous, so add the event listener in the response function for the URL loader.
Now your question sounds like you tried that but had some problem, so post that code and let us take a look.
Edit START
When I have multiple asynchronous calls that happen and I need something to happen after both of them are done I usually use booleans to store if each one has happened yet, then in a third function they both call I check both the booleans.
Here's how I'd do that:
protected function viewnavigatorapplication1_preinitializeHandler(event:FlexEvent):void
{
var loader1:Loader = new Loader();
var loader2:Loader = new Loader();
loader1.addEventListener(Event.COMPLETE, loader1_completeHandler);
loader1.load(new URLRequest("http://www.whitehouse.gov"));
loader2.addEventListener(Event.COMPLETE, loader2_completeHandler);
loader2.load(new URLRequest("http://www.nasa.gov"));
}
private function loader1_completeHandler():void
{
loader1Done = true;
//Maybe do some stuff here
moveOn();
}
private function loader2_completeHandler():void
{
loader2Done=true;
//Maybe do some stuff here
moveOn();
}
private function moveOn():void
{
if(!loader1Done||!loader2Done)
return;
//Do whatever needs to be done once both asynchronous events have completed
}
If this isn't your problem I think you need to provide more of the code in place of the comments that indicate other things happen, because it is a bit unclear.
For example I'm not sure what you mean by "The code in the constructor works if I dynamically assign a static value but if I try chaining to events together to get the dynamic value and dynamic assignment it crunches." Also since there's no example of the data or what the rootURL is there's no way to debug from here to understand what's going wrong.
Since there's no error we would need to be able to re-compile some portion of your code locally to give any better feedback.
Edit END
Blocking or synchronous calls are a horrible idea with regard to network communications due to the lack of reliability of networks and/or servers. If a front end application locked up to wait for a response before doing any other processing it would result in a horrible user experience, this is why there is no synchronous remote calls.
What happens with a synchronous call when the server bombs out, the client remains locked even though no response will result, the user can't interact with anything else in the front-end because it's waiting for said response which will never come? It's much better that remote calls of any sort are done in an asynchronous fashion, the same is true with local disk access in Java (or otherwise) where using asynchronous non-blocking calls is generally a better way to go to allow the other processes within an application to continue regardless of the state or use on the disk.
What you're doing should work just fine, you make a call to a remote service, it responds with some result and hits your "listener" or "callback" function then you want to do something with the results you can call another function, and the data is there.
It sounds to me like the only thing that's not happening is updates after the fact aren't being reflected in the UI, this is probably due to a lack of Bindable metadata/event dispatching for the properties. Have you inspected the result in the event that returns, have you put breakpoints in the method that is meant to be called after the data has returned? What you're doing is completely possible and it even looks like you have most of it right, but there's definitely something your doing wrong that's resulting in you not being able to make this work. If you can explain the behavior a bit clearer that will help, also what do you do here:
//THIS IS WHERE I TRIED TO CALL THE FUNCTION I NEED TO LOAD LATER

Flash debugger behaving differently from the player with AS3 and Events

Why this works on flash professional's debugger, but brings null on the compiled SWF?
var firstParameter:SomeObject = new SomeObject();
someLoader = new Loader();
someLoader.contentLoaderInfo.addEventListener(
Event.COMPLETE
, function(evt) {
onLoaded(evt, firstParameter);
}
, false
);
function onLoaded (evt:Event, param:SomeObject):void {
mcOnSceneForTracing.text = param; // this is used for SWF debugging
}
For the record:
To make it work without any issues this can be "solved" by creating a separate scope. However, here I'm wondering why, then, this example even works on the debugger at least.
And, please, if you have a better way other than using two anonymous functions to pass parameters, variables, values, whatever through an Event, do tell! I'm not willing to extend the Event, tho. Too 2005.
mcOnSceneForTracing is what I'm using to "trace" outside the debugger. Suggestions are also accepted here for better (and simpler) ways to do it! I've heard Vizzy is good, but haven't tried it yet.
My guess would be: When loading your resource from the debugger player, the operation finishes instantly, and thus firstParameter is available when your anonymous listener function is called, but when running the swf elsewhere, the load operation takes longer, and then the reference to firstParameter is lost, since it is a local variable.

as3 loading architecture

I have a large application that needs to ensure that various items are loaded (at different times, not just at startup) before calling other routines that depend on said loaded items. What i find problematic is how my architecture ends up looking to support this: it is either littered with callbacks (and nested callbacks!), or pre populated with dozens of neat little
private function SaveUser_complete(params:ReturnType):void
{
continueOnWithTheRoutineIWasIn();
}
and so forth. Right now the codebase is only perhaps 2500 lines, but it is going to grow to probably around 10k. I just can't see any other way around this, but it seems so wrong (and laborious). Also, i've looked into pureMVC, Cairngorm, and these methods seem equally tedious,except with another layer of abstraction. Any suggestions?
Well asynchronous operations always have this affect on code bases, unfortunately there's not really a lot you can do. If your loading operations form some sort of 'Service' then it would be best to make a IService interface, along with the appropriate MVC Style architecture and use data tokens. Briefly:
//In your command or whatever
var service:IService = model.getService();
var asyncToken:Token = service.someAsyncOperation(commandParams);
//some messaging is used here, 'sendMessage' would be 'sendNotification' in PureMVC
var autoCallBack:Function = function(event:TokenEvent):void
{
sendMessage(workOutMessageNameHere(commandParams), event.token.getResult());
//tidy up listeners and dispose token here
}
asyncToken.addEventListener(TokenEvent.RESULT, autoCallBack, false, 0, true);
Where I have written the words 'workOutMessageNameHere()' I assume is the part you want to automate, you could either have some sort of huge switch, or a map of commandParams (urls or whatever) to message names, either way best get this info from a model (in the same command):
private function workOutMessageNameHere(commandParams):String
{
var model:CallbackModel = frameworkMethodOfRetrivingModels();
return model.getMessageNameForAsyncCommand(commandParams);
}
This should hopefully just leave you with calling the command 'callService' or however you are triggering it, you can configure the callbackMap / switch in code or possibly via parsed XML.
Hope this gets you started, and as I've just realized, is relevant?
EDIT:
Hi, just had another read through of the problem you are trying to solve, and I think you are describing a series of finite states, i.e. a state machine.
It seems as if roughly your sequences are FunctionState -> LoadingState -> ResultState. This might be a better general approach to managing loads of little async 'chains'.
Agreeing with enzuguri. You'll need lots of callbacks no matter what, but if you can define a single interface for all of them and shove the code into controller classes or a service manager and have it all in one place, it won't become overwhelming.
I know what you are going through. Unfortunately I have never seen a good solution. Basically asynchronous code just kind of ends up this way.
One solution algorithm:
static var resourcesNeededAreLoaded:Boolean = false;
static var shouldDoItOnLoad:Boolean = false;
function doSomething()
{
if(resourcesNeededAreLoaded)
{
actuallyDoIt();
}
else
{
shouldDoItOnLoad = true;
loadNeededResource();
}
}
function loadNeededResource()
{
startLoadOfResource(callBackWhenResourceLoaded);
}
function callBackWhenResourceLoaded()
{
resourcesNeededAreLoaded = true;
if(shouldDoItOnLoad)
{
doSomething();
}
}
This kind of pattern allows you to do lazy loading, but you can also force a load when necessary. This general pattern can be abstracted and it tends to work alright. Note: an important part is calling doSomething() from the load callback and not actuallyDoIt() for reasons which will be obvious if you don't want your code to become out-of-sync.
How you abstract the above pattern depends on your specific use case. You could have a single class that manages all resource loading and acquisition and uses a map to manage what is loaded and what isn't and allows the caller to set a callback if the resource isn't available. e.g.
public class ResourceManager
{
private var isResourceLoaded:Object = {};
private var callbackOnLoad:Object = {};
private var resources:Object = {};
public function getResource(resourceId:String, callBack:Function):void
{
if(isResourceLoaded[resourceId])
{
callback(resources[resourceId]);
}
else
{
callbackOnLoad[resourceId] = callBack;
loadResource(resourceId);
}
}
// ... snip the rest since you can work it out ...
}
I would probably use events and not callbacks but that is up to you. Sometimes a central class managing all resources isn't possible in which case you might want to pass a loading proxy to an object that is capable of managing the algorithm.
public class NeedsToLoad
{
public var asyncLoader:AsyncLoaderClass;
public function doSomething():void
{
asyncLoader.execute(resourceId, actuallyDoIt);
}
public function actuallyDoIt ():void { }
}
public class AsyncLoaderClass
{
/* vars like original algorithm */
public function execute(resourceId:String, callback:Function):void
{
if(isResourceLoaded)
{
callback();
}
else
{
loadResource(resourceId);
}
}
/* implements the rest of the original algorithm */
}
Again, it isn't hard to change the above from working with callbacks to events (which I would prefer in practise but it is harder to write short example code for that).
It is important to see how the above two abstract approaches merely encapsulate the original algorithm. That way you can tailor an approach that suites your needs.
The main determinants in your final abstraction will depend on:
Who knows the state of resources ... the calling context or the service abstraction?
Do you need a central place to acquire resources from ... and the hassle of making this central place available all throughout your program (ugh ... Singletons)
How complicated really is the loading necessities of your program? (e.g. it is possible to write this abstraction in such a way that a function will not be executed until a list of resources are available).
In one of my project, I build custom loader which was basically wrapper class. I was sending it Array of elements to load and wait for either complete or failed event(further I modified it and added priority also). So I didn't have to add so many handlers for all resources.
You just need to monitor which all resources has been downloaded and when all resources complete, dispatch a custom event-resourceDownloaded or else resourcesFailed.
You can also put a flag with every resource saying it is necessary or compulsory or not, If not compulsory, don't throw failed event on failing of that resource and continue monitoring other resources!
Now with priority, you can have bunch of file which you want to display first, display and continue loading other resources in background.
You can do this same and believe me you'll enjoy using it!!
You can check the Masapi framework to see if it fulfills your needs.
You can also investigate the source code to learn how they approached the problem.
http://code.google.com/p/masapi/
It's well written and maintained. I used it successfully in a desktop RSS client I developed with Air.
It worked very well assuming you pay attention to the overhead while loading too many resources in parallel.