Why does my EVENT.ACTIVE trigger twice? - actionscript-3

When I add an EVENT.ACTIVATE listener to my project, and then alt-tab away and back to my project it triggers twice.
edit: shaunhusain and I seem to have found the cause of the problem, although without a solution. When running the standalone player version 11+ the event triggers 2x. When running standalone player version <11 or any version in the browser it triggers 1x. So it appears there may be a bug in recent versions of the flash player projector. I'm going to nail down the exact versions and report it to adobe and see what happens. Thanks to anyone who read this and tried to help!!
I want it to fire every time I change focus, I just don't want it to fire twice every time I change focus.
Why is this? Am I doing something wrong? What's the best way to prevent this behavior?
It seems like it would be a common question, but Google turned up nothing.
Code:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.addEventListener(Event.ACTIVATE, test);
}
private function test(e:Event):void
{
trace(e.target);
}
}
}
Actual result:
[object Stage]
[object Stage]
Desired result:
[object Stage]
It doesn't seem to make a difference whether I add the listener to the stage or anything else, the behavior is the same.
The same thing also happens with EVENT.DEACTIVATE. Others such as mouse up work fine.
My goal is to pause a game on EVENT.DEACTIVATE and unpause it on EVENT.ACTIVATE. The problem is that when the event fires twice, it calls the unpause function twice which has unwanted consequences.

ActionScript® 3.0 Reference for the Adobe® Flash® Platform says about this event:
Dispatched when the Flash Player or AIR application gains operating
system focus and becomes active. This event is a broadcast event,
which means that it is dispatched by all EventDispatcher objects with
a listener registered for this event. For more information about
broadcast events, see the DisplayObject class.
For me it looks like you want to prevent its designed behavior? I suppose it was designed to fire every time you change focus, or am I wrong? What do you want to accomplish? However this is an answer, so based on what you wrote - you can do a workaround by just removing a listener after he fired once:
private function test(e:Event):void
{
stage.removeEventListener(Event.ACTIVATE, test);
trace(e.target);
}
But I would recommend you to write something more about why are you using it and what want to accomplish if this is not satisfactory.

I've had the same issue in my AIR Mobile app.
To correct this issue, I've stored the last event name triggered for an Activate / Deactivate event. If it is attempted twice in a row, it just gets skipped with a return;
private static function onAppStateChanged(e:Event):void {
if (_STATE == e.type) {
return;
}
_STATE = e.type;
switch(_STATE) {
case Event.ACTIVATE: whenActivated.dispatch(); break;
case Event.DEACTIVATE: whenDeactivated.dispatch(); break;
}
}
At first, the value of _STATE begins with null, so that should allow it to pass through the first time around.
I bind both Event.ACTIVATE and Event.DEACTIVATE to the same listener, onAppStateChanged in my App's initialization method, like so:
_STAGE.addEventListener(Event.ACTIVATE, onAppStateChanged);
_STAGE.addEventListener(Event.DEACTIVATE, onAppStateChanged);
You can replace the Switch-Statement however you like, I just personally prefer using Robert Penner's AS3Signals (GitHub) to broadcast the resume/suspend signal across the App.

Related

Is better create a single object Event instead of always create another?

Usually when dispatching an Event (or custom Event) I use this:
function fireEvent():void {
dispatchEvent(new Event(Event.COMPLETE));
}
Is better use a single object to dispatch an event every time? Can I do this?
var myEvent:Event = new Event(Event.COMPLETE);
function fireEvent():void {
dispatchEvent(myEvent);
}
It would be a way better (eg create event pools) if it works. Unfortunately AS3 does some internal magic with event object during event flow which makes objects only one time usable (Sorry, by some reason I can't find proof quickly).
You can easily get confirmation by dispatching event second time, your listeners will not be triggered (may be it's true only for bubbling feature, not remember exactly), so you have to create a new instance of event object for every dispatchEvent call.
It doesn't worth it even if pooling works, I presume. Creating event objects isn't expensive in astionscript, adding event listeners is. You'd better put this effort on managing listeners and handlers which could easily become the performance buttleneck.

as3 symbol variables not initialized yet

I'm initializing symbols in my timeline, and trying to access the variables within those symbols, but they return 0 or undefined even though I set the variables in the symbol's timeline. For some reason the variables haven't been set yet, though the main timeline can see that they exist. How do I make the program wait until the variables have been set?
Best practice to work with classes, not coding in timeline and frames of MovieClip.
I assume you have MovieClip from designer and you want inject some logic to the specific frame. There are many options.
Events
You can trigger event in the specific frame, and you work in normal way (with classes and class members).
//Frame code
import flash.events.Event;
this.dispatchEvent(new Event("IntroDidFinish", true, true));
stop();
//Somewhere in class
myContainer.addEventListener("IntroDidFinish", onIntroFinish, false, 0, true);
function onIntroFinish(e: Event):void{
//Do your stuff
}
Events help you decouple logic from the design(predefined complex MovieClip, etc.)
Waiting for initialisation
As MovieClip reaches some frame, you should wait extra time for initialisation. Thats why 99.9% of AS3 developers don't like MovieClip as holder for any critical data or logic. It means if you call myMovieClip.goToAndStop(8); you can't get myMovieClip.someValue declared in 8 frame after goTo operation. If you still want to go with such approach, easiest solution for you will be Event.ENTER_FRAME, after goTo subscribe for ENTER_FRAME event, for only one update, and do your work ;)

Is Event TIMER always dispatched before TIMER_COMPLETE?

Is flash.utils.Timer object's event TIMER always dispatched before TIMER_COMPLETE?
During the 2nd event, I am nullifying stuff that are required during the 1st event; so their order is of prime importance. I checked the docs and there is no guarantee for their dispatching order.
In tests I've done it seems that this is the case, but I don't want to distribute publicly software without confirming first.
You can avoid this problem by using TimerEvent.TIMER only:
private function onTimer(event:TimerEvent)
{
// ...
if (timer.currentCount == timer.repeatCount) {
// timer is complete
}
}
I'm almost positive this is the case, since the code seems to be in the player itself I don't think you can get at the source to get a legitimate confirmation, however I have always seen this to be the case myself and from how the docs read it sounds as though a TIMER event would always be dispatched before the complete event
timerComplete
Dispatched whenever it has completed the number of requests set by Timer.repeatCount.
timer
Dispatched whenever a Timer object reaches an interval specified according to the Timer.delay property.
So I imagine the timerComplete is dispatched after it receives enough timer events that the currentCount equals the repeat count then a timerComplete is dispatched, however without being able to look at the code it's impossible for anyone to completely confirm this. Possibly you could look at the Gnash source to see how it's handled by that implementation of the player, but it's not necessarily the same in the normal Flash Player.

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.

Responding to an Event that May Have Already Occurred

I'm debating two approaches to a pretty typical problem: Knowing when an event occurs or responding to it immediately if it already HAS occurred.
In approach one, a user of MyLoader1 adds an event listener which will be fired immediately if the loader is already complete.
class MyLoader1 extends EventDispatcher
{
private var _isComplete:Boolean = false;
public override function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
super.addEventListener(type, listener, useCapture, priority, useWeakReference);
// if the operation is already complete, immediately notify listeners
if(_isComplete)
{
dispatchEvent(new Event(Event.COMPLETE));
}
}
}
class Application1()
{
function main():void
{
new MyLoader1().addEventListener(Event.COMPLETE, onComplete);
}
}
In approach 2, a user of MyLoader2 must first check the completion status of MyLoader2 before deciding whether to proceed or add a listener, which is fired later.
class MyLoader2 extends EventDispatcher
{
private var _isComplete:Boolean = false;
public function get isComplete():void
{
return _isComplete;
}
}
class Application2()
{
function main():void
{
var loader:MyLoader2 = new MyLoader2();
if(loader.isComplete)
{
// passing null just to simplify the example
onComplete(null);
}
else
{
loader.addEventListener(Event.COMPLETE, onComplete);
}
}
}
What advantages/disadvantages are there to each approach? Is there a design pattern out there that I could/should be using for this situation?
I'm leaning towards the first because it requires less knowledge of the Loader class and less code to leverage it. It could potentially create unwanted side effects when there are multiple listeners though, because the event will fire once for each time a listener is added.
The second method is understandable and easier to debug, but requires more up front work and seems to break encapsulation of the Loader.
I like your first approach better. I don't think that dispatching one event for each listener added is a problem, though; in fact, that's the very idea behind the event mechanism. If you have N objects that want to be notified whenever FooEvent occurs, you have to dispatch the event for each one whenever this event takes place.
Having said that, I wouldn't dispatch the event in the addEventListener method; I think that's the unwanted side effect, really. It goes against anyone's reasonable expectations. Adding a listener should not cause the event to fire. It should just register a listener. You should check whether the data is already loaded in your load function and dispatch the event there if the data is available (because at that point your load operation completed; not when you added the listener).
Another thing: I understand that you want to dispatch immediately if possible. But this has a problem, that can be serious and lead to annoying and not so obvious bugs. If you dispatch immediately you basically have 2 interfaces: one asynchronous and one synchronous. It's possible to handle this correctly in the calling code, but it requires more work and it's quite error prone, especially if you have chained events somewhere (I've made the error of having this kind of async/sync loader and I learned this the hard way).
It's much simpler and it makes almost no difference to delay the dispatching of the event in case the data is available right away. Just a tiny delay to make the code that handles the event run asynchronously (setTimeout(dispatchComplete,10) will do it), in a different stack frame that the code that called the loader. You'll save yourself some troubles and make your calling code simpler, which I think is what you're after.
Though slightly off topic, I would suggest you give signals a try. It depends on what kind of events you are using (ie. Mouse Events would still require the as3 Event so for some instances it might be a bit of extra work), but I've found signals a lot cleaner to implement, and for custom events, it is my preferred choice.
using a signals I usually set up one static var that acts as the main controller. I find this is better than the interconnected chain of Event Listeners and Dispatchers. You could have all the commands driving your app/game/website going through this one funnel.
The reason I'm bringing this up is that if you go this route, you essentially have a listener before you have the event. So if an object is created after the event has taken place, you could have it poll for whether an event occoured, and the addOnce() function is good for loaders and other events that are expected to happen once only. So while this does not answer your question, I hope it adds to the confusion :)
there's a link here to give you an idea of how it works
http://johnlindquist.com/2010/01/21/as3-signals-tutorial/