Can not retrieve data from completely Loaded static variable AS3 - actionscript-3

Basically I was trying to read an image in binary with help of URLLoader() and convert it to a image again in flash.
I wrote 2 static methods that one of them read image and set data properties to binary and other one is the COMPLETE handler.
In COMPLETE handler I convert the binary data to ByteArray and assign it to a static variable. then tried to access to it from Main Timeline but it won't work.
The problem is my temporary variable not fully loading the static variable and when I'm checking BytesAvailable it's something like only 2.
What I'm doing wrong?
The COMPLETE handler:
public static function compHand(e:Event):void
{
var myByteArray:ByteArray = URLLoader(e.target).data as ByteArray;
LoaderToObject.ImageBytes = myByteArray;
trace(myByteArray.bytesAvailable);
if (LoaderToObject.ImageBytes.length != myByteArray.length)
{
trace(myByteArray.length);
trace(LoaderToObject.ImageBytes.length);
}
else
{
trace("successFully loaded!");
}
}
public static function loadBin(FileUrl:String)
{
var imageBytes:ByteArray=new ByteArray();
var binUrl:URLRequest = new URLRequest(FileUrl);
var binLoader:URLLoader = new URLLoader(binUrl);
binLoader.dataFormat = URLLoaderDataFormat.BINARY;
binLoader.addEventListener(Event.COMPLETE,compHand);
//trace(LoaderToObject.ImageBytes);
trace(FileUrl);
}
The function I used in main timeLine:
function loadfile(e:MouseEvent):void
{
LoaderToObject.loadBin("chick.bmp");//send file to URLLoader
imageBytes= LoaderToObject.ImageBytes;
MakeImage2(imageBytes);
}
Please help me

Because URLLoader is asynchronous, so When you try to access imageBytes, the imageBytes hasn't been load complete yet.
Your need to pass callback function to loadBin for been called when load complete
Here is an example
The load class
Class MyLoader {
private var callback:function;
private var binLoader:URLLoader;
public function load(FileUrl:String, $callback:Function):void
{
callback = $callback;
//your code
var imageBytes:ByteArray=new ByteArray();
var binUrl:URLRequest = new URLRequest(FileUrl);
binLoader = new URLLoader(binUrl);
binLoader.dataFormat = URLLoaderDataFormat.BINARY;
binLoader.addEventListener(Event.COMPLETE,compHand);
//trace(LoaderToObject.ImageBytes);
trace(FileUrl);
}
private function compHand(e:Event):void
{
var myByteArray:ByteArray = URLLoader(e.target).data as ByteArray;
if (callback != null)
{
callback(myByteArray, this);
}
}
}
LoaderToObject's load function
//make MyLoader class live, it's important
private var loadValidDic:Dictionary = new Dictionary();
public static function loadBin(FileUrl:String, callback:Function)
{
var loader:MyLoader = new MyLoader();
loadValidDic[loader] = callback;
loader.load(FileUrl, internalComplete);
}
private static function internalComplete(ba:ByteArray, loader:MyLoader):void
{
var callback:function = loadValidDic[loader];
if (callback)
{
callback(ba);
loadValidDic[loader] = null;
delete loadValidDic[loader];
}
}
Used in timeline
function loadfile(e:MouseEvent):void
{
LoaderToObject.loadBin("chick.bmp", onComplete);//send file to URLLoader
}
private function onComplete(imageBytes:ByteArray):void
{
MakeImage2(imageBytes);
}

Related

Error hanlder for FileStream - AS3 AIR

I'm saving an object to a file using FileStream. The object I'm saving has variables in it:
var saveObj:Object = new Object()
saveObj['FirstName']="Georges"
saveObj['LastName']="St-Pierre"
MY question is this: How do I make an error handler for a variable missing when I load the File? For example 'Firstname' is missing. How do I do that? This is the code I have but it doesn't work.
private function F_loadData():void {
folder = File.documentsDirectory.resolvePath("saved projects");
var file:File = folder.resolvePath("mySave.adktf");
var stream:FileStream = new FileStream();
stream.addEventListener(Event.COMPLETE, completeHandler);
stream.addEventListener(ProgressEvent.PROGRESS, progressHandler);
stream.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
stream.openAsync(file, FileMode.READ);
var myLoadedObj:Object = stream.readObject();
stream.close()
trace(myLoadedObj.MiddleName)
}
private function completeHandler(event:Event):void {
trace("load Complete")//not final. Just for testing
}
private function progressHandler(event:ProgressEvent):void {
// ...
}
//I was hoping the error would call this function
private function errorHandler(event:IOErrorEvent):void {
trace("Error found")//not final. Just for testing
}
trace(myLoadedObj.MiddleName) should return an error and i was hoping that it would call the error Handler function that I made, but it didn't. It still returns an error. So how and what type of error handler should I use?
Since you are opening your file asynchronously, you need to wait to use readObject until after the complete event.
The error handler you've defined is only applicable to the loading of the file. SO if there is a problem opening the file the error handler will be called, any other kind of error is outside that scope.
Try something like this:
private var stream:FileStream;
private function F_loadData():void {
folder = File.documentsDirectory.resolvePath("saved projects");
var file:File = folder.resolvePath("mySave.adktf");
if(file.exists){
stream = new FileStream();
stream.addEventListener(Event.COMPLETE, completeHandler);
stream.addEventListener(ProgressEvent.PROGRESS, progressHandler);
stream.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
stream.openAsync(file, FileMode.READ);
//now wait for it to load
}else{
//file doesn't exist, do something
}
}
private function completeHandler(e:Event):void {
trace("load Complete")//not final. Just for testing
var myLoadedObj:Object = stream.readObject();
stream.close();
stream = null;
if(!myLoadedObj.MiddleName || myLoadedObj.MiddleName == ""){
//Middle name is missing or empty, do something
}
if(!myLoadedObj.FirstName || myLoadedObj.FirstName == ""){
//First name is missing or empty, do something
}
}
You may be better suited to using a custom class for your save object, something like this:
package {
public class SaveObject {
public var middleName:String;
public var lastName:String;
//any other properties
public function validate():Boolean {
//write some validation
//if you want lazy validation, you could do this: (untested)
for (var i in obj){
if(obj[i] is String && (obj[i] == null || obj[i] == "")){
return false;
}
}
return true;
}
}
}
Then, you can do this: (in your constructor)
flash.net.registerClassAlias("SaveData",SaveData);
Then you can do the following:
var mySaveData:SaveData = new SaveData();
//set properties
stream.writeObject(mySaveData);
//then later
var mySaveData:SaveData = stream.readObject();
if(!mySaveData.validate()){
//do something, it's invalid
}

loadermax to get qualified class name of the swf

The typical as3 code would be like this
private function load():void {
var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
if(Security.sandboxType == Security.REMOTE) {
loaderContext.securityDomain = SecurityDomain.currentDomain;
}
loader.contentLoaderInfo.addEventListener(Event.INIT, handleInit);
loader.load(new URLRequest("capture.swf"), loaderContext);
}
private function handleInit(event:Event){
var className:String = getQualifiedClassName(loader.content);
var classRef:Class = loader.contentLoaderInfo.applicationDomain.getDefinition(className) as Class;
var captureModule = new classRef();
addChild(captureModule as DisplayObject);
}
now while using greensock's loadermax, how can I access the qualified class name, it's reference, create an object myself and add to display.
loaderMax.append(new SWFLoader("capture.swf", {name:"capture"}));
loaderMax.append(new SWFLoader("filter.swf", {name:"filter"}));
loaderMax.load();
the loadComplete function
function completeHandler(event:LoaderEvent): void {
trace(event.target + " is complete");
var capture = loaderMax.getContent("capture");
trace(getQualifiedClassName(capture)); //want to reach the custom class of the loaded sf
}
turns out that the loaded swf has a property loaderInfo.loader that you can access to use the loader.
var loader = loaderMax.getContent("capture").rawContent.loaderInfo.loader;
this.data["capture"] = loader.contentLoaderInfo.applicationDomain.getDefinition(getQualifiedClassName(loaderMax.getContent("capture").rawContent)) as Class;

Dynamic Object Name in AS3

I have this code in my MXML project, I want to get dynamic Stream connection for different and dynamic usernames.
private var inStream:NetStream;
private function listenStream(user:String):void
{
this["inStream"+user] = new NetStream(connection);
this["inStream"+user].play(user);
}
private function closeStream(user:String):void
{
//clear stream listener
this["inStream"+user].close();
}
But this code is not worked, How can i build dynamic object names in ActionScript3?
Thanks alot
Try Dictionary
import flash.utils.Dictionary
private var streamDict:Dictionary = new Dictionary();
private function listenStream(user:String):void
{
var key:String = getKey(user);
var lastStream:NetStream = streamDict[key] as NetStream;
if (lastStream)
{
//close the last stream or do sth else
}
else
{
streamDict[key] = new NetStream(connection);
streamDict[key].play(user);
}
}
private function closeStream(user:String):void
{
var key:String = getKey(user);
//clear stream listener
var stream:NetStream = streamDict[key] as NetStream ;
if (stream)
{
stream.close();
}
//delete the stream
streamDict[key] = null;
delete streamDict[key];
}
private function getKey(user:String):String
{
return "inStream" + user;
}

Putting Urlloader in a Class

I have searched on google en different pages i found the problem but not the solution.
I have a class i made and that class is called WebServiceController:
public class WebServiceController
{
private var url:String;
private var post:Object=new Object();
private var loader:URLLoader = new URLLoader();
private var postVariable:String="";
private var getVariable:String="";
private var Geladen:Boolean=false;
public function WebServiceController()
{
}
public function postUrlData(u:String,p:Object):String
{
url=u;
post=p;
var urlReq:URLRequest = new URLRequest (url);
var i:int=0;
for(var key:String in post)
{
//trace(key +" = " + post[key]);
if(i==0)
{
// urlVars.key = post[key];
postVariable=postVariable+""+key+"="+post[key];
}
else
{
//urlVars.key = post[key];
postVariable=postVariable+"&"+key+"="+post[key];
}
i++;
}
//trace(postVariable);
var urlVars:URLVariables = new URLVariables(postVariable);
//trace(urlVars);
// Add the variables to the URLRequest
urlReq.data = urlVars;
urlReq.method = URLRequestMethod.POST;
// Add the URLRequest data to a new Loader
//loader.load(urlReq);
// Set a listener function to run when completed
loader.addEventListener(Event.COMPLETE, onLoaderComplete);
// Set the loader format to variables and post to the PHP
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.load(urlReq);
function onLoaderComplete(event:Event):void
{
return loader.data;
}
}
Now from my movieclip i call the next function but it says undefined:
var wb:WebServiceController = new WebServiceController();
trace(wb.postUrlData(url,post));
I dont know how to solve this. I tried different things but it keeps saying undefined.
The URLLoader.load call is executed asynchronously so the data has not been returned when you attempt to trace it out in the class that instantiates your WebServiceController class.
To access the data in the parent class, your best bet is probably to dispatch an event from the WebServiceController class when the data has loaded and catch it in the parent class.
WebServiceController:
public function postUrlData(u:String, p:Object):void
{
url=u;
post=p;
var urlReq:URLRequest = new URLRequest (url);
var i:int=0;
for(var key:String in post)
{
//trace(key +" = " + post[key]);
if(i==0)
{
// urlVars.key = post[key];
postVariable=postVariable+""+key+"="+post[key];
}
else
{
//urlVars.key = post[key];
postVariable=postVariable+"&"+key+"="+post[key];
}
i++;
}
//trace(postVariable);
var urlVars:URLVariables = new URLVariables(postVariable);
//trace(urlVars);
// Add the variables to the URLRequest
urlReq.data = urlVars;
urlReq.method = URLRequestMethod.POST;
// Add the URLRequest data to a new Loader
//loader.load(urlReq);
// Set a listener function to run when completed
loader.addEventListener(Event.COMPLETE, onLoaderComplete);
// Set the loader format to variables and post to the PHP
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.load(urlReq);
}
private function onLoaderComplete(event:Event):void
{
// We can pass the event on like this
dispatchEvent(event);
}
Parent class:
public function initWebServiceController():void
{
var wb:WebServiceController = new WebServiceController();
wb.addEventListener(Event.COMPLETE, onWebServiceControllerDataLoaded);
wb.postUrlData(url, post);
}
private function onWebServiceControllerDataLoaded(event:Event):void
{
// The event target is the URLLoader instance. We can
// access the loaded data via its data property
trace(URLLoader(event.target).data);
}

How to run function only when parameter variable has been assigned?

I need a way to wait running the parseCSV command until the readFile event has updated the content of importData. I have seen a few things about custom event dispatchers but cannot quite figure out how to use them in my situation.
private var importData : String;
public function importFile(event:MouseEvent):void {
var data:String = chooseFile();
parseCSV(importData);
}
public function chooseFile ():String {
var filetype:FileFilter = new FileFilter("CSV Files(*.csv)","*.csv");
var file:File = File.userDirectory;
file.browseForOpen("Select CSV file to import", [filetype]);
file.addEventListener(Event.SELECT, readFile);
return importData;
}
public function readFile (event:Event):void {
var filestream:FileStream = new FileStream();
filestream.open(event.target as File, FileMode.READ);
importData = filestream.readUTFBytes(filestream.bytesAvailable);
filestream.close();
}
You'll either need to add some callbacks or add some event listeners. I prefer callbacks:
function importFile(...) {
choseFile(function(file:File) {
readFile(file, parseCSV);
});
}
function choseFile(callback:Function) {
...
file.addEventListener(Event.SELECT, function(event:Event) {
callback(File(event.target));
});
}
function readFile(file:File, callback:Function) {
var data = ... read data from file ....;
callback(data);
}
What about just adding the line in the readFile function?
public function readFile (event:Event):void {
var filestream:FileStream = new FileStream();
filestream.open(event.target as File, FileMode.READ);
importData = filestream.readUTFBytes(filestream.bytesAvailable);
parseCSV(importData);
filestream.close();
}
The command will be executed as soon as importData is set.
If you wish to the custom events route, you need to dispatch your own custom Event. Each Event has a type parameter which is just a string to identify it with. For example Event.CHANGE is the same as using "change".
static public const CUSTOM = "myCustomEvent";
public function someConstructor():void {
addEventListener(CUSTOM, onCustomEvent);
}
public function testDispatch():void{
dispatchEvent(new Event(CUSTOM));
}
private function onCustomEvent(e:Event):void{
trace("custom event Dispatched");
}
So you could try something like this.
public function importFile(event:MouseEvent):void {
addEventListener(CUSTOM, onImport);
var data:String = chooseFile();
}
private function onImport(e:Event):void {
parseCSV(importData);
}
public function readFile (event:Event):void {
var filestream:FileStream = new FileStream();
filestream.open(event.target as File, FileMode.READ);
importData = filestream.readUTFBytes(filestream.bytesAvailable);
dispatchEvent(new Event(CUSTOM));
filestream.close();
}