Actionscript dispatch event fails and solution.

The Problem:

A event too close to the instantiation of an object is not being fired, I believe the speed of the code execution is too fast for the listener to be able to register for the event.

Lets take a look at the following class to understand the issue.

[as]package application.views
{

import flash.display.Sprite;
import flash.events.Event;

public class TestView extends Sprite
{

public static const NAME : String = “TestView”;
public static const THE_EVENT : String = NAME + “The_Event”;

private var holder : Sprite;

public function TestView ( )
{

init();

}

private function init () : void
{
holder = new Sprite;
holder.graphics.beginFill(0x000000)
holder.graphics.drawRoundRect(0, 0, 100, 100, 0);
holder.graphics.endFill();
addChild(holder);

dispatchEvent ( new Event ( THE_EVENT))
}

}

}[/as]

In the example above what we are doing is dispatching an event after the creation of a simple object. If you notice the call to the init function is right after the construction of this specific object, in this case the object that is listening for that specific event is never able to “hear” the event, although it has been fired.

Here is the construction of the TestView and the listening for the event:

[as]private var testView : TestView;
testView = new TestView;
testView.addEventListener ( TestView.THE_EVENT, theEventHandler ) ;

private function theEventHandler ( event : Event ) : void
{
trace(“Event Fired”);
}[/as]

The Solution

The solution is very simple, add a delay as low as 1/1000 before the code execution.

[as]package application.views
{

import flash.display.Sprite;
import flash.events.Event;
import flash.utils.setTimeout;

public class TestView extends Sprite
{

public static const NAME : String = “TestView”;
public static const THE_EVENT : String = NAME + “The_Event”;

private var holder : Sprite;

public function TestView ( )
{

//delay the execution of init by 1/1000
setTimeout(init, 1);
//init();

}

private function init () : void
{
holder = new Sprite;
holder.graphics.beginFill(0x000000)
holder.graphics.drawRoundRect(0, 0, 100, 100, 0);
holder.graphics.endFill();
addChild(holder);

dispatchEvent ( new Event ( THE_EVENT))
}

}

}[/as]

Conclusion

There are ways to go around this issue, that is for certain but being able to find where your problem is located at is important to provide the right solution at the right time. I am going to do some more research in regards to why this specific problem happens at a lower level but for now it allows me to trust that the listener is going to be able to “listen” for a specific event.

Am I happy with this solution? NO. but for this specific application I am working on I need to make sure all the elements are in place before continuing the chain of events rather than just trusting that items are drawn or attached on the display list.

4 thoughts on “Actionscript dispatch event fails and solution.”

  1. Here’s what’s happening:

    Before you add your event listener, you’re constructing your TestView. This means, of course, that you’re executing your TestView’s constructor method. Remember, though, that the method can’t fully execute until all of its internal statements have executed. That means you can’t finish your construction until the internal init() function call is complete. As you know, an ActionScript statement won’t execute until the previous line has finished executed. That means that when you call
    testView = new TestView;
    testView.addEventListener…

    …your testView object will not only execute the constructor, but the init function as well – BEFORE moving to the next line with the event listener.

    When I’ve run into this problem, I’ve tried a slightly different solution. Rather than using a private init() method and calling it from the object’s constructor, I use a public init() method and call it from the document class. This gives me total control of when the init method is called, so I can defer calling it until after the event listener is added. For example:

    testView = new TestView();
    testView.addEventListener(…);
    testView.init();

    It’s easy to ensure that the init function is called only once; ensuring this serves to largely eliminate the hazards of making the init() method public.

  2. Thanks LB. The issue was trying to find a way around to firing the event after instantiation. Granted we could put the call to the init (or any other method) later during the life of the application but in this case I was tring to figure out the way to add the listener and make the instationation as close to each other as possible.

    In most cases the methods will run long enough that you won’t run into this issues or having to create this kind of hacks but this instance was rare where the execution of the init function was extremely fast thus not allowing the player to listen/fire on time.

    interesting enough after working on this small issue I found the following on the documentation:

    If the event listener is being registered on a node while an event is being processed on this node, the event listener is not triggered during the current phase but can be triggered during a later phase in the event flow, such as the bubbling phase.

    Which is exactly what I was trying to do and placing the delay was “fixing” the issue.

  3. Sorry but this is a developer fail.

    “In most cases the methods will run long enough” – excuse me but this is wrong wrong wrong (honestly other words come to my mind).

    There is no timing issue here. Each line of code, no matter how complex the operation or subfunctions are, will happen one after the other. Period.

    I hope you meant: in most cases the class will dispatch an event after it receives another event during a later phase, like a mouse click or a loader completion.

    Using a timer to workaround your “code design problems” is a bad idea if you know how inefficient it is. Calling a public init() method is still a much cleaner option. And actually as far as your sample class is concerned, you don’t have to wait for any event: your class init is a blocking operations.

    Finally as far as your sample is concerned, you don’t need to dispatch an event to notify that the init is finished.

  4. Hi Philippe,

    I know my solution was not the most elegant at all if you notice on my very last statement I say:

    “Am I happy with this solution? NO. but for this specific application I am working on I need to make sure all the elements are in place before continuing the chain of events”

    I have found how unreliable a time out is and I should an updated post with a better solution.

    Thanks for your comments which help us all to realize that at times a “solution” for specific project can always be improved on.

Comments are closed.