Weird crash in AIR application - actionscript-3

I have a crash that only happens with the installed application I can't make it cvrash in the IDE(Flash Builder debug or run option)
After a long time of commenting and uncomenting code I found the problem and I am posting the code below
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:ns="generic_components.*"
creationComplete="windowedapplication1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
//import core.Logger;
import mx.controls.Alert;
import mx.events.FlexEvent;
import spark.events.TextOperationEvent;
protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
{
//Logger.init();
}
public static function humanFromCamelCase(txt:String):String{
var res:String=txt.charAt(0);
//Logger.write("camel case for "+txt);
for (var i:int=1;i<txt.length;i++)
{
// Logger.write("camel iter "+i);
var c:String=txt.charAt(i);
//Logger.write("camel char is "+c);
if(c==c.toUpperCase())
{
res=res+" "+c;
}
else
res=res+c;
}
return res;
}
protected function test_clickHandler(event:Event):void
{
Alert.show(humanFromCamelCase("CompanyId"));
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:Button id="test" label="TEST" click="test_clickHandler(event)"/>
</s:WindowedApplication>
Also see a web sample here http://ploscariu.com/crash/TestWeb.html (may be not there in the future)
What is weird about this crash:
1 I have no idea what happens
2 The usual crash handler in the player does not show up
3 is not crashing in the development enviroment IDE
4 if i uncomment those Logger.write then the code works on my machine fine(it could not work on all machines), the Logger.write writes the sting in a file and is placed in another project swf (I did not included the logger code)
I a, assuming that the call to Logger.write can cause a delay or something similar
It is something wrong in my code or the player is buggy? or the compiler??
Any ideas?
Edit:
-is not the logger i use since the error happens when I am not using it like in the sample code or page, no logger the app it crashes
-i get no dialog from Flash with a crash report

This is so incredibly odd!!!! I have NO idea why this happening (yet)... but I have a workaround:
Instead of res=res+c, use res+=c:
public static function humanFromCamelCase(txt:String):String{
var res:String=txt.charAt(0);
for (var i:int=1;i<txt.length;i++)
{
var c:String=txt.charAt(i);
if(c === c.toUpperCase())
{
res += " " + c;
}
else
res += c;
}
return res;
}

I have no idea why you're having an error, however, I would replace the function with this instead:
public static function humanFromCamelCase(txt:String):String{
return txt.replace(/([A-Z])/g, ' $1').replace(/^ /, "");
}
Haven't tested it, but you get the idea. This is a much simpler and faster approach.
I also thought of another way:
public static function humanFromCamelCase(txt:String):String{
return txt.split(/(?=[A-Z])/).join(' ');
}

Related

Adobe Flash Builder (1046: Type was not found or was not a compile-time constant)

I am using Adobe Flash Builder for the first time, and I am trying to create a Flex project. I am going to be embedding a flash game in a nodeJS app, so I am using https://github.com/sinnus/socket.io-flash. Socket.io-flash requires websocketJS, and I have added both the socket.io-flash folder (straight from github), and the websocketJS folder (also from github) to Flash Builder's source path (so the files should be getting recognized when they are imported - and they are). I am getting this error for two of the imports:
1046: Type was not found or was not a compile-time constant: SocketIOEvent.
and...
1046: Type was not found or was not a compile-time constant: SocketIOErrorEvent.
Like I said, the import lines are fine (no errors being thrown there) - the errors come from the method declarations - here is my .mxml file:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:VGroup>
<s:TextArea id="textArea" width="300" height="300"/>
<s:Button label="Connect" click="onConnectClick()"/>
<s:Button label="Send" click="onSendClick()"/>
<s:Button label="Disconnect" click="onDisconnectClick()"/>
</s:VGroup>
<fx:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
import io.socket.flash.ISocketIOTransport;
import io.socket.flash.ISocketIOTransportFactory;
import io.socket.flash.SocketIOErrorEvent;
import io.socket.flash.SocketIOEvent;
import io.socket.flash.SocketIOTransportFactory;
import io.socket.flash.WebsocketTransport;
import io.socket.flash.XhrPollingTransport;
private var _socketIOTransportFactory:ISocketIOTransportFactory = new SocketIOTransportFactory();
private var _ioSocket:ISocketIOTransport;
private function onConnectClick():void
{
_ioSocket = _socketIOTransportFactory.createSocketIOTransport(XhrPollingTransport.TRANSPORT_TYPE, "localhost:9000/socket.io", this);
_ioSocket.addEventListener(SocketIOEvent.CONNECT, onSocketConnected);
_ioSocket.addEventListener(SocketIOEvent.DISCONNECT, onSocketDisconnected);
_ioSocket.addEventListener(SocketIOEvent.MESSAGE, onSocketMessage);
_ioSocket.addEventListener(SocketIOErrorEvent.CONNECTION_FAULT, onSocketConnectionFault);
_ioSocket.addEventListener(SocketIOErrorEvent.SECURITY_FAULT, onSocketSecurityFault);
_ioSocket.connect();
}
**private function onSocketConnectionFault(event:SocketIOErrorEvent):void**
{
logMessage(event.type + ":" + event.text);
}
**private function onSocketSecurityFault(event:SocketIOErrorEvent):void**
{
logMessage(event.type + ":" + event.text);
}
private function onDisconnectClick():void
{
_ioSocket.disconnect();
}
**private function onSocketMessage(event:SocketIOEvent):void**
{
if (event.message is String)
{
logMessage(String(event.message));
}
else
{
logMessage(JSON.encode(event.message));
}
}
private function onSendClick():void
{
_ioSocket.send({type: "chatMessage", data: "Привет!!!"});
_ioSocket.send({type: "chatMessage", data: "Delirium tremens"});
_ioSocket.send("HELLO!!!");
}
**private function onSocketConnected(event:SocketIOEvent):void**
{
logMessage("Connected" + event.target);
}
**private function onSocketDisconnected(event:SocketIOEvent):void**
{
logMessage("Disconnected" + event.target);
}
private function logMessage(message:String):void
{
textArea.text = textArea.text + message + "\n";
}
]]>
</fx:Script>
</s:Application>
I have encased the lines where the errors are thrown from with '**' (it is having trouble with what is being imported for some reason). In my Flash Builder project I have, in the libs folder, the websocketJS folder, and the socket.io-flash folder, and they have both been added to the source path. Any help would be greatly appreciated - thanks!
The function "logMessage" is simply not defined. Use "trace" as alternative (e.g. trace(event.type + ":" + event.text);

selectedIndex in List after Alert

I have a list with an ArrayCollection dataProvider. In my program, there is a button the user can click to perform a function for the selectedIndex of the List, but an Alert is shown first asking them if they are sure they want to perform the action. After the user answers the Alert, the action is performed on the selectedIndex of the list.
My problem is that selectedIndex = -1 after the Alert window CloseEvent, even though it is clearly selected. I got around this by performing validateNow() on the list in the code for the Alert CloseEvent.
My question: Why do I have to do this and am I doing something wrong? Or is this normal/best practice? Also, is there a better/best practice to check a List to see if something is selected besides using try-catch. I don't want the end user to see the generated error if nothing is selected.
Code:
//Note: "fl" is a class with "friendsList" bindable ArrayCollection; for the sake of keeping this short I will not include it
private function _removeFriendClick(event:MouseEvent):void
{
try {
if (this.friendsList.selectedIndex != -1) {
Alert.show("Are you sure you want to remove "+this.fl.friendsList[this.friendsList.selectedIndex].label+" as a friend?", "Remove Friend", Alert.YES | Alert.CANCEL, this, this._removeFriendConfirm, null, Alert.CANCEL);
}
} catch (e:Error) { }
}
private function _removeFriendConfirm(event:CloseEvent):void
{
this.friendsList.validateNow();
trace(this.friendsList.selectedIndex);
}
So, with the above code, if you take out the validateNow(), an exception is thrown because it thinks the selectedIndex is -1.
I would do it in this way:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.CloseEvent;
[Bindable]private var friendsList:ArrayCollection = new ArrayCollection([{data:"111", label:"Don"}, {data:"222", label:"John"}]);
private function onBtnRemove():void
{
laFriend.text = "";
try
{
if (cbFriends.selectedIndex != -1)
{
Alert.show("Are you sure you want to remove " + cbFriends.selectedItem.label + " as a friend?", "Remove Friend", Alert.YES | Alert.CANCEL, this, this._removeFriendConfirm, null, Alert.CANCEL);
}
} catch (e:Error) { }
}
private function _removeFriendConfirm(event:CloseEvent):void
{
laFriend.text = "Selected friend: " + cbFriends.selectedItem.label;
}
]]>
</fx:Script>
<mx:VBox>
<s:ComboBox id="cbFriends" dataProvider="{friendsList}"/>
<s:Button id="btnRemove" label="Remove" click="onBtnRemove()"/>
<s:Label id="laFriend" text=""/>
</mx:VBox>
</s:Application>
Do you perform selection just before you call your handler?
If you set selectedIndex, you can't get it back immediately because of the livecycle - value shall be commited before you can read it.
Your validateNow forces that commit. However, it shall happen later without enforcing it manually.

How to run a function after the canvas has changed in ActionScript 3.0?

Please understand: I am a total beginner at Actionscript and anything like Actionscript, and though I generally have some idea of what I'm doing as a programmer, I'm having some setbacks in self-learning this language and Flex Builder. Right now I'm trying to make a very simple implementation where a label effectively has its text added to multiple times over the first few seconds that the program is run. The problem I'm running into is that I can't just put all that into one function + one call on that function, as changes to the label's text are apparently not seen until that function runs its full course.
So I tried using a viewstack and cloning the canvas a few times, giving each canvas's version of that label a different bit of text. Then I set the initialize function for the viewstack to change the canvases on regular intervals over the first few seconds. But that didn't work either, as the difference isn't seen until the function runs its full course.
So then I tried putting function calls on the individual canvases' initialize attributes, and those functions aren't being called at all apparently.
What the heck? I know this probably isn't even the way that you're supposed to animate something in ActionScript or Flex, but I still would like to know how to approach the problem this way for future reference. What am I missing? Thanks!
As you've noticed, changes to the displayed output of your program can't happen in the middle of executing a function that you've written. ActionScript is single-threaded, which means that none of the framework code that updates the screen can run while your function is running.
If you're interested in learning exactly what happens in order to update the screen, do a search for "flex component lifecycle" and read some of the stuff you find. It's a bit advanced, but it was the thing that really helped me understand how the Flex framework works.
Anyway, on to your real question - how to animate something. There are many ways, but for your case of progressively adding text to a label, I'd probably use the Timer class.
Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private var timer:Timer;
private var words:Array = ["The", "quick", "brown", "fox"];
private function startTimer(event:FlexEvent):void
{
timer = new Timer(1000, 1);
timer.addEventListener(TimerEvent.TIMER, updateText);
timer.start();
}
private privatefunction updateText(event:TimerEvent):void
{
theLabel.text += words.shift() + " ";
if (words.length > 0)
{
timer.reset();
timer.start();
}
}
]]>
</fx:Script>
<s:Label id="theLabel" text="" creationComplete="startTimer(event)"/>
</s:Application>
A basic approach would be to use data binding for the label value, and setTimeout() or setInterval() to cause the delay between updates.
Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
initialize="init()"
minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
[Bindable]
private var displayString:String = "Detonation in ";
private var count:int = 5;
private var timer:uint;
private function init():void {
timer = setInterval(updateDisplay, 1000);
}
private function updateDisplay():void {
displayString += count + ".. ";
if (--count == 0) {
clearInterval(timer);
}
}
]]>
</fx:Script>
<s:Label text="{displayString}"/>
</s:Application>

Display List Architecture in Flex

I'm asked about Display List architecture in Flex at an interview. Later I searched about it but no use. Any help is appreciated.
The Display List is like a tree. Imagine the Stage object as the base of the tree. Think of MovieClips and Sprites that are added to the stage as branches and leaves coming off of the tree. The Display List also serves as the core for the event system in AVM2. Objects that are attached to the DisplayList (that is, they themselves or their parent, parents parent etc end up connecting to the Stage) can "bubble" events through the Display List.
Anyway that's my short little way of explaining it but you can get much more detailed information from these links:
http://www.adobe.com/devnet/flash/quickstart/display_list_programming_as3.html
http://tv.adobe.com/watch/colin-moocks-lost-actionscript-weekend/the-display-list/
seems like the question should really sound as follows:
when you write <s:Application> (or any other SkinnableContainer / UIComponent) in your mxml code -- what is the structure of the resulting display list?
so you should do something like:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" applicationComplete="onAppComplete();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import mx.controls.Alert;
import mx.core.UIComponent;
import spark.components.SkinnableContainer;
private function onAppComplete(e:* = null):void {
trace(parseList(stage));
//Alert.show(parseList(stage));
}
private function parseList(uic:DisplayObjectContainer, prefix:String = '>'):String{
prefix = prefix || '>';
var retStr:String = '';
for (var i:int = 0; i < uic.numChildren; i++ ) {
retStr += prefix + uic.getChildAt(i).name + '\n';
if (uic.getChildAt(i) is DisplayObjectContainer) {
retStr += parseList(uic.getChildAt(i) as DisplayObjectContainer, prefix + '>');
}
}
return retStr;
}
]]>
</fx:Script>
<s:SkinnableContainer>
<s:Panel>
<mx:UIComponent>
</mx:UIComponent>
</s:Panel>
</s:SkinnableContainer>
</s:Application>
(or maybe more complex) and study the output
the code above outputs
>root1
>>NewFile1
>>>ApplicationSkin3
>>>>Group4
>>>>>Group5
>>>>>>SkinnableContainer6
>>>>>>>SkinnableContainerSkin7
>>>>>>>>Group8
>>>>>>>>>Panel9
>>>>>>>>>>PanelSkin10
>>>>>>>>>>>RectangularDropShadow11
>>>>>>>>>>>Group12
>>>>>>>>>>>>Group13
>>>>>>>>>>>>instance36
>>>>>>>>>>>>Group14
>>>>>>>>>>>>>Group15
>>>>>>>>>>>>>>Label16
>>>>>>>>>>>>>>>instance33
>>>>>>>>>>>>>>>instance37
>>>>>>>>>>>>>Group17
>>>>>>>>>>>>>>UIComponent18

FlexEvent.APPLICATION_COMPLETE never called in simple app

I've got a really simple flex application, with a main file Rec.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="215" minHeight="138" width="215" height="138" backgroundAlpha="0.0">
<fx:Script>
<![CDATA[
var rec:LRec = new LRec();
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
And an AS3 class:
package
{
import mx.core.Application;
import mx.events.FlexEvent;
public class LRec extends Application
{
public function LRec()
{
trace("CONSTRUCTED");
addEventListener(FlexEvent.APPLICATION_COMPLETE, this.mainInit);
}
/**
* After the application startup is complete, debug
*/
public function mainInit(event:FlexEvent):void {
trace("COMPLETE");
}
}
}
The trace ("CONSTRUCTED") is printed, but not "COMPLETE" -- it looks like the FlexEvent.APPLICATION_COMPLETE event is never registering. Any ideas why?
Also, this is the first time I've really done this sort of programming, so if anything else looks wrong, please tell me!
I've updated your code below with some comments on where you were going wrong. If you have any other questions feel free to ask.
Test.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="215" minHeight="138" width="215" height="138" backgroundAlpha="0.0"
initialize="handle_initialize(event)"
>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
// Probably want to keep your rec object around
private var rec:LRec;
// Construct your LRec instance in the Application's inititialize state,
// rather than declaring it statically.
protected function handle_initialize(event:FlexEvent):void
{
// Construct a new LRec instance, assign it to our private variable.
this.rec = new LRec();
// The <s:Applicaiton instance we define in this mxml is the object that
// will actually dispatch the applicationComplete event, so we want to
// listen for that here and pass it on to our LRec instance's mainInit
// method when it fires.
this.addEventListener(FlexEvent.APPLICATION_COMPLETE, this.rec.mainInit);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
LRec.as
package
{
import mx.events.FlexEvent;
// Don't inherit from Application, as you've already defined your application
// in your mxml, and you should have only one Application instance per application.
public class LRec
{
public function LRec()
{
trace("CONSTRUCTED");
// Doesn't need the event listener anymore.
// Do any instantiation needed.
}
/**
* After the application startup is complete, debug
*/
public function mainInit(event:FlexEvent):void {
trace("COMPLETE");
// Do any of the work that needs to wait for the applicationComplete
// event to fire.
}
}
}
Here's a good article (though a bit dated) on the Flex Instantiation Model.