Using Actionscript Worker to loop function to make it faster - actionscript-3

My current code that allow application to upload data inside of Excel file into the AIR app is as follows;
import lib.xlsxreader.Worksheet;
import lib.xlsxreader.XLSXLoader;
public class Main extends MovieClip
{
private var fileGet: File = new File();
private var xloader: XLSXLoader = new XLSXLoader();
public function Main()
{
fileGet = File.applicationDirectory;
fileGet.addEventListener(Event.SELECT, selectExcel)
xloader.addEventListener(Event.COMPLETE, uploadComplete);
button.addEventListener(MouseEvent.CLICK, selectFile);
}
private function selectFile(e: MouseEvent): Void
{
fileGet.browseForOpen("Select File");
xloader.load(fileGet.nativePath);
}
private function uploadComplete(e: Event): Void
{
ws = xloader.worksheet("[Name of the worksheet]");
rowStart = 7;
rowEnd = ws.rows;
for (var i = rowStart; i <= rowEnd; i++)
{
//transferring data from excel into sqlite
}
}
}
The code above is not my complete code, I just shorten it to the relevant code. Let me know if you need more information.
Right now the code is transferring data from 30 columns and 1000++ rows from Excel file for about 10 minutes which is kinda slow and make the AIR app appear 'hang' or 'frooze' during uploading.
It come to my attention that I can use Worker API in Actionscript to fasten this process but for the life of me, I can't exactly figuring out how to restructuring my code to allow Worker API in my code.
I have read through example from here, here and here, but I still can't make heads or tails on this issue.
As far as my understanding goes, my code //transferring data from excel into sqlite should be included in class CountResult from this example...?
Can someone help me on this problem. Take note that I'm a self-learn amateur programmer trying to learn to make dekstop app using Adobe Animate.

Related

Haxe Map Memory Cleanup Issue

So I have been using Haxe for a while and it has occurred to me recently that I don't really get what happens on some other the non-flash targets as far as memory cleanup. I mean 'new'ing everything and dumping it by setting references to null gives me this feeling that there are memory leakages, but I can't seem to find the documentation I'm looking for.
Specifically I use dictionaries/maps a decent amount. Like this:
var items:Map<String, MyObject> = new Map();
items.set("someKey", new MyObject(args...));
// Later
items["someKey"].doSomething();
items["someKey"].setVal(2);
...
// When Finished
items.remove("someKey");
The last line there just dumps my object somewhere into oblivion and hopefully gets garbage collected (at least on the Flash target).
I put together a little program just to see the cleanup in action on Flash/Neko and then change it for other targets, but I am failing to even see the cleanup on the Flash Neko target. Here is the project code:
package;
import openfl.display.Sprite;
import openfl.events.Event;
import haxe.ds.StringMap;
import openfl.events.KeyboardEvent;
import openfl.ui.Keyboard;
class Main extends Sprite
{
private var keypressID:Int;
private var itemID:Int;
private var dict:StringMap<Sprite>; // Using this since I read Map<String, T> just compiles to StringMap<T>.
public function new()
{
super();
addEventListener(Event.ENTER_FRAME, init);
}
private function init(event:Dynamic):Void
{
removeEventListener(Event.ENTER_FRAME, init);
// Entry point.
keypressID = 0;
itemID = 0;
dict = new StringMap();
stage.addEventListener(KeyboardEvent.KEY_UP, keyPress);
}
private function keyPress(event:Dynamic):Void
{
if (Std.is(event, KeyboardEvent) && cast(event, KeyboardEvent).keyCode == Keyboard.A)
{
trace('ID: $keypressID - Adding Item');
keypressID += 1;
for (i in 0...10000)
{
itemID += 1;
dict.set('$itemID', new Sprite());
}
}
else if (Std.is(event, KeyboardEvent) && cast(event, KeyboardEvent).keyCode == Keyboard.R)
{
trace('ID: $keypressID - Removing Items');
keypressID += 1;
removeItems();
}
// Force garbage collector to run.
else if (Std.is(event, KeyboardEvent) && cast(event, KeyboardEvent).keyCode == Keyboard.C)
{
trace('ID: $keypressID > Starting GC');
keypressID += 1;
forceGarbageCollection();
}
}
private function removeItems()
{
trace('ID: $keypressID > Remove All Item');
for (val in dict.keys())
{
dict.remove(val);
}
dict = new StringMap();
}
private function forceGarbageCollection():Void
{
neko.vm.Gc.run(true); // This does not work.
}
}
I run this on Windows and under task manager, my neko process only grows and never shrinks. Its gets up to 500MB quick when hitting 'A'. I then 'R' to remove all references to the items, but they never get collected it seems even when I force the GC.
I also tried storing openfl.util.Timer objects with event listeners attached to them to do traces and they never seem to get collected either. They just keep tracing. Now I suspect that may be because of the event listener reference, but am sure I have seen that trick in other AS3 memory leak tracking code.
Am I missing something or doing something wrong?
Edit:
I have modified the above question to reflect this, but I was mistaken about Flash player. I did get the memory to be reclaimed when running in the Flash player using flash.system.System.gc(); It seems the problem may be specific to neko which my question still addressed.

Returning a string in Action Script 3.0

I'm really not familiar with Action Script 3 at all but I am with other languages.
I'm hoping someone could help me.
I'm attempting to make a modification to JWplayer so that an rtmp stream is retrieved via a PHP script rather than it being supplied in the HTML.
The code I currently have is below:
function useData(event:Event):void {
var data:String = event.target.data.toString();
}
/** Load content. **/
override public function load(itm:PlaylistItem):void {
_item = itm;
_position = 0;
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, useData);
loader.load(new URLRequest("http://192.168.0.12/phpauth/play1.php"));
// Set Video or StageVideo
if(!_video) {
_video = new Video(320, 240);
_video.smoothing = true;
_video.addEventListener('renderState', renderHandler);
// Use stageVideo when available
if (_stageEnabled && RootReference.stage['stageVideos'].length > 0) {
_stage = RootReference.stage['stageVideos'][0];
_stage.viewPort = new Rectangle(0,0,320,240);
_stage.addEventListener('renderState', renderHandler);
}
attachNetStream(_stream);
}
// Load either file, streamer or manifest
if (_item.file.substr(0,4) == 'rtmp') {
// Split application and stream
var definst:Number = _item.file.indexOf('_definst_');
In the load function the file name to play is held in _item.file. I'm trying to make a call to a php script which then overwrites the value in _item.file. I've confirmed that the php is being called but I don't know how to get the data from the data string in the useData function into the _item.file string.
Any help would be really appreciated - I suspect this is a simple one but my lack of AS3 knowledge is making it really difficult.
Thanks,
Your problem basically about how to access a local variable in an event handler. A quick and dirty way can be to have an anonymous function used as a handler like:
loader.addEventListener(Event.COMPLETE, function(event:Event):void {
var data:String = event.target.data.toString();
_item.file = data;
});
This approach would work, because this anonymous function has access to the local variables inside load function as is. But, you need to be cautious that the anonymous function uses the variable exactly as the calling function is using. So, let's say there is a loop in load function and _item changes in every iteration of the loop. For that scenario, when load handler gets called, its _item would also have changed to the object which was last assigned to _item.
A far cleaner and OO approach can be to have a handler class like:
package {
public class LoadHandler {
private var _item:PlaylistItem;
public function LoadHandler(item:PlaylistItem) {
_item = item;
}
public function loadHandler(event:Event):void {
var data:String = event.target.data.toString();
_item.file = data;
}
}
and then have loader.addEventListener(Event.COMPLETE, (new LoadHandler(_item)).loadHandler). Hope that helps. BTW, LoadHandler could be made more generic to take and array of objects to be used and a callback function. loadHandler function, then could just call callback function with that array of objects.
If you are returning a simple string from PHP you should be able to use
event.target.data;
e.g. from PHP... echo "hello";
var data:String = event.target.data
You could try tracing the response to ensure you are getting something back from PHP.
You can either test this from within the IDE or install the Debug version of the Flash Player browser plugin.
trace("Response from PHP: "+event.target.data);
_item.file = event.target.data;
trace("_item.file: "+_item.file);

Trigger a function on main timeline from a class?

I am trying to trigger a function on the main timeline in my FLA from a class file. I can usually find the solution sifting through forum posts but all the ones i look at just aren't helping.
heres the code i have as of now, but it doesn't seem to be working.
//this is the code in my as3 class file
var e:Event = new Event("runFunc",true) dispatchEvent(e)
//here is the code in my .fla
addEventListener("runFunc", initialization);
I know using code in the FLA is a dirty method of coding but i am trying to add to a pre-existing game i had built previously.
A simple solution would be to migrate your code off the timeline with this method..
// class file
public function Main() {
//constructor
this.addFrameScript(1, frameOneFunc);
initialization();
}
private function frameOneFunc(){
This is essentially code in timeline for frame one.
}
i dont quite follow you glad, Are you saying to cut my code out of the fla and paste it in the frameOneFunc in the class file?
Here is a little more code to go off of.
.fla code(the function im trying to run)
function initialization();
{
//random code...
}
code in my class file
public function frame1()
{
this.savedstuff = SharedObject.getLocal("myStuff");
this.btnSave.addEventListener(MouseEvent.CLICK, this.SaveData);
this.btnLoad.addEventListener(MouseEvent.CLICK, this.LoadData);
if (this.savedstuff.size > 0)
{
//trying to trigger function here...this is my failed code below
//MovieClip(parent).initialization();
//var e:Event = new Event("runFunc",true)
//dispatchEvent(e)
//dispatchEvent(new Event("initialization"));
this.nameField.y = 800
this.note.y = 800
this.btnSave.y = 800
this.btnLoad.y = 800
this.tigger.y = 0;
trace(this.savedstuff.data.username);
this.nameField.text = this.savedstuff.data.username;
this.note.gotoAndStop(4);
}
return;
}

i have an error(s), it's not working, which are the errors [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.net.*;
import com.adobe.serialization.json.*;
public class ScreenCategories extends Sprite {
public var myLoader:URLLoader;
public var filePath:String;
public var myReq:URLRequest;
public function ScreenCategories() {
// constructor code
reLoad();
}
// Constructor: Create an array of three categories
public function reLoad()
{
lastButtonEndedY = 35;
/*
In our real app, we would load in the categories from our database (via a JSON)
Hint: Saving the Objects into the array at the index that equals the ID is advised
*/
filePath = "getCategories.php"; //declare path and file name
myReq = new URLRequest(filePath); //create URLRequest to access the file
myLoader = new URLLoader(); //create URLLoader to load the file
//add event listener to run fileLoaded function when loading is complete
myLoader.removeEventListener(Event.COMPLETE, loadComplete);
myLoader.addEventListener(Event.COMPLETE, loadComplete);
//add event listener to listen for any error thrown during loading process
myLoader.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
myLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
myLoader.load(myReq); //start loading a file with our URLLoader instance
}
//loading complere so print content of a text file to our Text Field
function loadComplete(e:Event):void
{
var jsonstring:String = myLoader.data;
var categories:Array = JSON.decode(jsonstring);
for (var count:int = 0; count < categories.length; count++) {
var aCategory:Object = category[count];
trace(aCategory.categoryname);
trace(aCategory.categoryid);
}
///////////////
// Consider that it would be more responsible to add these to an array and maintain
// which are being added/deleted, then we could create a print function!
///////////////
}
//if any error was thrown, event was also dispatched and now you can print
//the error description to the text field.
public function ioErrorHandler(e:IOErrorEvent):void
{
trace("There was a problem loading "+filePath+": "+e);
}
}
}
// for each "category" in our list (Array)...
for (var count in categories)
{
// Create a button for each of the categories that exist in our Array
var aCategory:BtnCategory = new BtnCategory(categories[count].category);
// Add the BtnCategory to the stage
aCategory.x = 0;
aCategory.y = lastButtonEndedY;
aCategory.name = categories[count].id; // give it a unique name!
addChild(aCategory);
lastButtonEndedY += (aCategory.getHeight() + 1);
}
addEventListener(MouseEvent.CLICK, mouseClicked);
This is supposed to work on Action script 3 for a mobile app where i need a category list that will take me to a product list and the a product.... but i'm working first on the category list where the values are read from JSON, i already have a getCategory.php document where my json was returned correctly..... but when i run the swf it says error....
To me it looks like filePath = "getCategories.php"; is your problem.
When you run locally or in your dev environment it will look for that php page in the same directory that the SWF is in which will probably work fine for you. But when you publish to a phone that is no longer the location of the php page.
As such you will probably get the IO error since the server does not exist.
[EDIT]
Well now that you finally posted the error I can see what your issue is.
type was not found or was not a compile-time constant: Event
Is stating that it can not find the Event class.
Looking at your code you are not importing it either.
The closest you come to it is the MouseEvent.
So instead of just importing the MouseEvent try this.
import flash.events.*;

Debugging a release only flash issue

I've got an Adobe Flash 10 program that freezes in certain cases, however only when running under a release version of the flash player. With the debug version, the application works fine.
What are the best approaches to debugging such issues? I considered installing the release player on my computer and trying to set some kind of non-graphical method of output up (I guess there's some way to write a log file or similar?), however I see no way to have both the release and debug versions installed anyway :( .
EDIT: Ok I managed to replace my version of flash player with the release version, and no freeze...so what I know so far is:
Flash: Debug Release
Vista 32: works works
XP PRO 32: works* freeze
I gave them the debug players I had to test this
Hmm, seeming less and less like an error in my code and more like a bug in the player (10.0.45.2 in all cases)... At the very least id like to see the callstack at the point it freezes. Is there some way to do that without requiring them to install various bits and pieces, e.g. by letting flash write out a log.txt or something with a "trace" like function I can insert in the code in question?
EDIT2: I just gave the swf to another person with XP 32bit, same results :(
EDIT3:
Ok, through extensive use of flash.external.ExternalInterface.call("alert", "..."); I managed to find the exact line causing the problem (I also improved exception handling code so rather than freeze it told me there was an "unhandled" exception). The problem now is what on earth is flashes problem with this with the release player on some machines...
particles.push(p);
Which causes a TypeError #1034 on said platforms. Particles is a Vector.<Particle>, p is a Particle. I tested with getQualifiedClassName and got:
getQualifiedClassName(p) = ::Particle
getQualifiedClassName(particles) = __AS3__.vec::Vector.<::Particle>
Any ideas why this is a problem and what to do to make it work?
EDIT4:
Ok I seem to have solved this. The Particle class is just a simple internal class located after the package {...} in the action script file using it. I moved this into its own file (particle.as) and made it a proper public class in my package, and problem solved.
Maybe its a flash bug or maybe I missed the memo about not using internal classes in vectors or something, although if that's the case I would have expected something or other (either at compile time or with debug runtimes) to disallow it explicitly, e.g. some error on the "private var particles:Vector.<Particle>;" line. If I get a chance I guess I'll take a look at contacting the Adobe flash team concerning this or something.
Thanks for help giving debugging tips which I guess is more along the original questions lines :)
This is a long shot, but are the Particles the objects that you are clicking? If so then catching the event in the wrong phase of bubbling, and pushing event.target (assuming it to be a Particle) could cause that problem.
Whatever the problem, I have something that should help you debug. A class that creates a pseudo trace window in your SWF, much nicer than extinterfacing to javascript. I've forgotten who wrote it, but I feel like it's Senocular. I use it any time I need to get traces back from end users.
Just drop it in the default package for your project, call stage.addChild(new Output());, and then to trace call Output.trace("A message");
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.GradientType;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.text.TextFieldAutoSize;
/**
* Creates a pseudo Output panel in a publish
* swf for displaying trace statements.
* For the output panel to capture trace
* statements, you must use Output.trace()
* and add an instance to the stage:
* stage.addChild(new Output());
*
*/
public class Output extends Sprite {
private var output_txt:TextField;
private var titleBar:Sprite;
private static var instance:Output;
private static var autoExpand:Boolean = false;
private static var maxLength:int = 1000;
public function Output(outputHeight:uint = 400){
if (instance && instance.parent){
instance.parent.removeChild(this);
}
instance = this;
addChild(newOutputField(outputHeight));
addChild(newTitleBar());
addEventListener(Event.ADDED, added);
addEventListener(Event.REMOVED, removed);
}
// public methods
public static function trace(str:*):void {
if (!instance) return;
instance.output_txt.appendText(str+"\n");
if (instance.output_txt.length > maxLength) {
instance.output_txt.text = instance.output_txt.text.slice(-maxLength);
}
instance.output_txt.scrollV = instance.output_txt.maxScrollV;
if (autoExpand && !instance.output_txt.visible) instance.toggleCollapse();
}
public static function clear():void {
if (!instance) return;
instance.output_txt.text = "";
}
private function newOutputField(outputHeight:uint):TextField {
output_txt = new TextField();
//output_txt.type = TextFieldType.INPUT;
output_txt.border = true;
output_txt.borderColor = 0;
output_txt.background = true;
output_txt.backgroundColor = 0xFFFFFF;
output_txt.height = outputHeight;
var format:TextFormat = output_txt.getTextFormat();
format.font = "_sans";
output_txt.setTextFormat(format);
output_txt.defaultTextFormat = format;
return output_txt;
}
private function newTitleBar():Sprite {
var barGraphics:Shape = new Shape();
barGraphics.name = "bar";
var colors:Array = new Array(0xE0E0F0, 0xB0C0D0, 0xE0E0F0);
var alphas:Array = new Array(1, 1, 1);
var ratios:Array = new Array(0, 50, 255);
var gradientMatrix:Matrix = new Matrix();
gradientMatrix.createGradientBox(18, 18, Math.PI/2, 0, 0);
barGraphics.graphics.lineStyle(0);
barGraphics.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, gradientMatrix);
barGraphics.graphics.drawRect(0, 0, 18, 18);
var barLabel:TextField = new TextField();
barLabel.autoSize = TextFieldAutoSize.LEFT;
barLabel.selectable = false;
barLabel.text = "Output";
var format:TextFormat = barLabel.getTextFormat();
format.font = "_sans";
barLabel.setTextFormat(format);
titleBar = new Sprite();
titleBar.addChild(barGraphics);
titleBar.addChild(barLabel);
return titleBar;
}
// Event handlers
private function added(evt:Event):void {
stage.addEventListener(Event.RESIZE, fitToStage);
titleBar.addEventListener(MouseEvent.CLICK, toggleCollapse);
fitToStage();
toggleCollapse();
}
private function removed(evt:Event):void {
stage.removeEventListener(Event.RESIZE, fitToStage);
titleBar.removeEventListener(MouseEvent.CLICK, toggleCollapse);
}
private function toggleCollapse(evt:Event = null):void {
if (!instance) return;
output_txt.visible = !output_txt.visible;
fitToStage(evt);
}
private function fitToStage(evt:Event = null):void {
if (!stage) return;
output_txt.width = stage.stageWidth;
output_txt.y = stage.stageHeight - output_txt.height;
titleBar.y = (output_txt.visible) ? output_txt.y - titleBar.height : stage.stageHeight - titleBar.height;
titleBar.getChildByName("bar").width = stage.stageWidth;
}
}
}
Judging by when the freeze occurs, try to pinpoint some possibilities for what the offending code may be, and use De MonsterDebugger to check variables etc.
EDIT:
I'm pretty certain that the actual call stack is only available to you in the debug versions of the Flash Player / AIR. Still, it may be useful in the debug player to trace the stack from within the handler for the button to see if anything is out of place:
var err:Error = new Error(“An Error”);
trace(err.getStackTrace());
FYI the getStackTrace method is only available in the debug player, so there is no way to write it to a log.txt in production.