Deal connection lost in ActionScript 3 - json

I have this code:
public function Json2Me(_urlJSON:String) {
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest();
request.url = _urlJSON;
loader.addEventListener(Event.COMPLETE, onLoaderComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR,informadorIO);
loader.load(request);
}
private function onLoaderComplete(e:Event):void{
var loader:URLLoader = URLLoader(e.target);
JSONEnviado = com.adobe.serialization.json.JSON.decode(loader.data);
dispatchEvent(new Event("LanzaJSON"));
}
public function informadorIO(e:Event):void{
trace(e);
}
I need to protect my code against connection lost, so what I have to do to keep my project running?

You can catch the IO errors on url loader:
loader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
private function ioErrorHandler(event:IOErrorEvent):void {
// URLLoader io failed
trace("ioErrorHandler: " + event);
// retry Json2Me maybe? How many times before you fail completely? Notify user?
Json2Me("https://someurl.com/xxxxx")
}
Also the uncaughtErrorEvents on the Loader/LoaderInfo can catch things like not even having a network connection.
LoaderInfo.uncaughtErrorEvents: to detect uncaught errors in code
defined in the same SWF. Loader.uncaughtErrorEvents: to detect
uncaught errors in code defined in the SWF loaded by a Loader object.
Example:
loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtError);
private function onUncaughtError(e:UncaughtErrorEvent):void {
e.preventDefault();
trace("onUncaughtError!!! - " + e.toString());
// Notify user of failure?...
}

You can also use a HTTPStatusEvent which can give use the returned HTTP status ( or even the returned HTTP response headers for an AIR app ) :
var url_loader:URLLoader = new URLLoader()
url_loader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, on_http_status); // works only for AIR
url_loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, on_http_status);
url_loader.load(new URLRequest('http://www.example.com'))
function on_http_status(e:HTTPStatusEvent): void
{
trace(e.type); // gives, for example : httpStatus
trace(e.status); // gives, for example : 200
}
Hope that can help.

Related

How to catch Stream Error in ActionScript

I have the following piece of code, which attempts to GET a publicly hosted (AWS S3) file.
private function ShowS3Message():void
{
// Attempt to download file from AWS
var descriptor:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = descriptor.namespaceDeclarations()[0];
var url:String = "https://s3.amazonaws.com/some-url/file-" + descriptor.ns::versionLabel.split(".").join("-") + ".txt";
var urlRequest:URLRequest = new URLRequest(url);
// Set up callback function
try{
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, awsFetchCallback);
loader.load(urlRequest);
}catch(error:Error){}
}
This is the callback function:
/**
* Callback function for AWS message file
*/
private function awsFetchCallback(event:Event):void
{
var data = event.target.data;
// show dialog
var msb:InformationMessageBox = new InformationMessageBox();
msb.mText = data;
msb.open(this, true);
}
When the file exists, there is no problem, and the code runs fine.
When the file doesn't exist, this throws a StreamError, despite the catch block.
what am I missing?
You should capture the IO error event, there is not exception thrown when the file does not exist.
loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
and then create your own error handler function.
more details in the doc here :
https://help.adobe.com/fr_FR/FlashPlatform/reference/actionscript/3/flash/net/URLLoader.html
If you just want to drown the error (because you seem to know the file may not exist sometimes) it is sufficient to create an empty error event handler.

AS3: Reusing URLLoader, URLRequest, and URLVariables instances

My Flash project uses URLLoader.load a lot to load content from a web server and post to a php page. Should I reuse my URLLoader, URLRequest, and URLVariables instances, or should I create new ones each time? If I should create new ones each time, do the old ones need to be disposed of somehow?
You should most certainly never ever ever reuse any instances related to external operations and you should thoroughly dispose of them the very moment you don't need them. The overhead of Garbage Collector (GC) working on these objects is literally nothing next to the nightmare mess you might get into once your external operations collide via sharing the same operational instances.
URLVariables and URLRequest do not need any special treatment, just set null to any variables referencing them and ensure that method, where they were assigned to local variables, do not produce any function closures. Well, set URLRequest.data to null to break this reference.
URLLoader, on the other hand, needs to be pushed around a bit:
If URLLoader.data is a ByteArray, then you should ByteArray.clear() it (unless you need it).
Set the URLLoader.data to null.
Initially subscribe all error handlers with weak references (fifth argument of addEventListener set to true) and don't unsubscribe them. Weak keys won't affect the GCs judgement while keeping the subscriptions might save you from occasional Unhandled Error Event case.
Certainly do unsubscribe all non-error handlers.
In all the handlers, first check if Event.target is a valid URLLoader instance to avoid handling an event from a dead/disposed URLLoader.
Call URLLoader.close() just in case. Yes, after all of above is done.
Below is the class I use to load things in a simple way. It is built on the same principles I listed above. It allows loading text/binary data and also provides some proof against unstable network: you can set the repeatCount argument to higher values to provide fail-safe loading if you know that requests tend to fail sometimes.
Usage:
// Load binary data over unstable network.
DataFiles.load("data.dat", onData, true, 10);
// Load XML file as text over a stable network or from the local storage.
DataFiles.load("setup.xml", onSetup);
function onData(source:ByteArray):void
{
if (!source)
{
// Loading failed. Error case.
}
else
{
// File is loaded normally.
}
}
function onSetup(source:String):void
{
try
{
var aSetup:XML = new XML(source);
// Process loaded XML normally.
}
catch (fail:Error)
{
// The source is either null or an invalid XML string.
// Loading is failed, basically. Error case.
}
}
Implementation:
package simplify
{
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLLoaderDataFormat;
public class DataFiles
{
static private var list:Vector.<DataFiles> = new Vector.<DataFiles>;
static public function load(url:String, handler:Function, binary:Boolean = false, repeatCount:int = 1):void
{
var aLoader:DataFiles = new DataFiles;
aLoader.url = url;
aLoader.binary = binary;
aLoader.handler = handler;
aLoader.repeatCount = repeatCount;
list.push(aLoader);
aLoader.start();
}
private var url:String;
private var binary:Boolean;
private var handler:Function;
private var loader:URLLoader;
private var repeatCount:int;
private function start():void
{
loader = new URLLoader;
if (binary) loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE, onComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR, onError, false, 0, true);
loader.load(new URLRequest(url));
}
private function destroyLoader():void
{
if (!loader) return;
loader.removeEventListener(Event.COMPLETE, onComplete);
var aDead:Loader = loader;
loader = null;
aDead.data = null;
aDead.close();
}
private function onComplete(e:Event):void
{
if (e.target != loader) return;
var aResult:* = loader.data;
var aHandler:Function = handler;
destroy();
destroyLoader();
aHandler(aResult);
}
private function onError(e:IOErrorEvent):void
{
if (e.target != loader) return;
destroyLoader();
repeatCount--;
if (repeatCount >= 0)
{
start();
}
else
{
var aHandler:Function = handler;
destroy();
aHandler(null);
}
}
private function destroy():void
{
var anIndex:int = list.indexOf(this);
if (anIndex > -1) list.splice(anIndex, 1);
handler = null;
url = null;
}
}
}

AS3 image loading content is always null

I have a problem with my assets loader I've created for my flash app. In a function I try to load an external image and return it from this function. My problem is that I always get loader.content set to null. This how my code looks like:
public static function loadImage(path:String):BitmapData
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, check);
if (path == "")
loader.load(new URLRequest("images/default.png"));
else
loader.load(new URLRequest("images/" + path));
var image:Bitmap = new Bitmap((loader.content as BitmapData));
return image.bitmapData;
}
public static function check(e:Event):void
{
trace("Loading completed");
e.target.removeEventListener(Event.COMPLETE, check);
}
Any ideas???? I've also included my event listener which does launch.
I'm pretty sure it's because the loader works asynchronously, but I have no idea how to modify it to be able to return the image from the function.
Thanks in advance!
I'm pretty sure it's because the loader works asynchronously
Correct
but I have no idea how to modify it to be able to return the image from the function
There is no way to do that.
Why?
Because it is asynchronous.
You can't return a result of a request straight after the request has been made.
The execution of the code does not pause and wait for the response to come back, so your function will hit the return statement before you get the data, and that is why it is returning null.
The only way to handle this is to listen for the response (Event.COMPLETE) and run a callback function after the response from the server has been received.
So following your code example, you could do:
private static var _callback :Function;
public static function loadImage(path:String, callback:Function):void
{
_callback = callback;
// ....
and then:
public static function check(e:Event):void
{
// ...
_callback( whateverYouWantToReturnGoesHere );
This should work assuming that you only have one image loaded at a time (as your methods are static), otherwise you will need to implement some sort of request queue handling.
I hope this helps.
Your getting a 'null' because you're referring to loader.content too soon. Here's a simplified version that works, just fine, in a timeline:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, check);
loader.load(new URLRequest("images/default.png"));
function check(e:Event):void
{
var bmd:BitmapData = new BitmapData(195,130,false,0xFFFFFFFF)
var image:Bitmap = new Bitmap(bmd);
bmd.draw(loader.content);
trace(loader.content);
trace("Loading completed");
addChild(image);
e.target.removeEventListener(Event.COMPLETE, check);
}
You can put it back into a form suitable for your classes.
You should say:
var bitmapData:BitmapData;
and
var image:Bitmap = new Bitmap(event.target.content.bitmapData)
instead of
var image:Bitmap = new Bitmap((loader.content as BitmapData));

ActionScript 3: How to remove EventListener with anon functions

I have written code as follows.
Problem is that I can't remove Event.COMPLETE event listener and when I call the loadData function twice or more, it works 2 times or more. Sorry for my bad english and worse explanation but I need to fix it today and I don't know what to do.
I think the code is pretty obvious. please help!
var ldr:URLLoader = new URLLoader();
function loadData(text_place, scrollbar, fileURL:String):void {
text_place.wordWrap = true;
var f:TextFormat = new TextFormat();
f.align = TextFormatAlign.RIGHT;
text_place.setTextFormat(f);
ldr.dataFormat = URLLoaderDataFormat.TEXT;
ldr.load(new URLRequest(fileURL));
ldr.addEventListener(Event.COMPLETE, function ldr_complete(evt:Event){
initText(text_place, ldr.data, scrollbar);
});
ldr.addEventListener(IOErrorEvent.IO_ERROR, loadError);
}
function initText(text_place:TLFTextField, fileContent, scrollbar):void {
ldr.removeEventListener(IOErrorEvent.IO_ERROR, loadError);
text_place.htmlText = "";
text_place.tlfMarkup = fileContent;
scrollbar.update();
trace("Data loaded");
}
function loadError(e:IOErrorEvent):void {
trace("Error loading an external file.");
}
just avoid writing function enclosures and extend the scope of the complete function's passed arguments so it can access them.
var ldr:URLLoader = new URLLoader();
var text_place:TextField;
var scrollbar:Object; //or whatever it is
function loadData(text_place, scrollbar, fileURL:String):void
{
var f:TextFormat = new TextFormat();
f.align = TextFormatAlign.RIGHT;
text_place.wordWrap = true;
text_place.setTextFormat(f);
scrollbar = scrollbar;
ldr.dataFormat = URLLoaderDataFormat.TEXT;
ldr.load(new URLRequest(fileURL));
ldr.addEventListener(IOErrorEvent.IO_ERROR, loadError);
ldr.addEventListener(Event.COMPLETE, loadComplete);
}
function initText(text_place:TLFTextField, fileContent, scrollbar):void
{
removeLoaderEventListeners();
text_place.htmlText = "";
text_place.tlfMarkup = fileContent;
scrollbar.update();
trace("Data loaded");
}
function loadError(e:IOErrorEvent):void
{
removeLoaderEventListeners();
trace("Error loading an external file.");
}
function loadComplete(evt:Event):void
{
removeLoaderEventListeners();
initText(text_place, ldr.data, scrollbar);
}
function removeLoaderEventListeners():void
{
ldr.removeEventListener(IOErrorEvent.IO_ERROR, loadError);
ldr.removeEventListener(Event.COMPLETE, loadComplete);
}
if you want to stop listening for an event after it triggered, you can unregister the anonymous listener in itself:
ldr.addEventListener(Event.COMPLETE, function(event:Event):void
{
event.target.removeEventListener(event.type, arguments.callee);
// ... do whatever you need to do here
});
But if you also want to stop listening for other events from the same dispatcher when it completes, such as your IOErrorEvent.IO_ERROR listener, you'd still need a reference to that listener to remove it.
There is a simpler way. Instead of removing event listeners, close the loader.
ldr.close();
Per the documentation:
Closes the load operation in progress. Any load operation in progress
is immediately terminated. If no URL is currently being streamed, an
invalid stream error is thrown.

URLLoader handler in child movie not being called

Hi I am writing a flex application that has a MainMovie that loads flex programs (ChildMovie) depending on what the user selects in the MainMovie. below is some pseudocode to help me describe my problem hopefully.
class MainMovie{
private var request:URLRequest = new URLRequest();
public function callPHPfile(param:String, loader:URLLoader,
handlerFunction:Function):void {
var parameter:URLVariables=new URLVariables();
parameter.param = param;
request.method = URLRequestMethod.POST;
request.data = parameter;
request.url = php file on server;
loader.addEventListener(Event.COMPLETE, handlerFunction);
loader.load(request);
}
}
Class ChildMovie {
private var loaderInChild:URLLoader = new URLLoader();
public function handlerInChild(e:Event):void {
process data....
loaderInChild.removeEventListerner(Event.COMPLETE, handlerInChild);
}
private function buttonClickHandler(e:Event):void{
Application.application.callPHPfile(param, loaderInChild, handlerInChild)
}
}
I can see that the callPHPfile function is being executed and received xml data from in httpFox, the problem is that the code in the handlerInChild function is not being executed. What am I doing wrong here?
It was a runtime error. I forgot that i uninstalled flash player debugger in firefox and it didn't show. in the handlerInChild function, there is a line
var data:XML = loader.data;
it should be
var data:XML = XML(loader.data);
and the code will run as expected.