Listeners and AsBroadcaster
         by senocular

AsBroadcaster
We'll get into more usage with Listeners, but not before dipping a little into the AsBroadcaster object and seeing what it really accomplishes. This object is closely tied to listeners, more than you may think. Each one of those event broadcasting objects listed before (Key, Mouse, Selection, Stage, TextField) was initialized behind the scenes by Flash using AsBroadcaster. This is what enabled them to broadcast that event for listeners to handle.

The AsBroadcaster object itself, despite its presumed intimidation, is simply a generic object with one method, initialize. This is used on other objects to transform those objects into broadcasting capable objects. In doing so, it adds three new methods and a new property to the transformed object. These methods are addListener, removeListener, broadcastMessage and the property, _listeners. addListener lets you add a listener to your new broadcasting object. removeListener lets you remove one. broadcastMessage is the command that the initialized object runs to generate an event to be sent out to the listeners (like onMouseDown) while _listeners is a list of all the listeners associated with the broadcast object. So, for the usage of AsBroadcaster, we get:

AsBroadcaster.initialize(objToBroadcast);
objToBroadcast.addListener(listenObj);
objToBroadcast.removeListener(listenObj);
objToBroadcast.broadcastMessage("event");
objToBroadcast._listeners;

Note that you do not create instances of the AsBroadcaster object as you would with other objects using the new keyword. It is simply a container object for the initialize function, which could just have easily been a stand alone function.. The only time AsBroadcaster is actually written in code is when an object is initialized to become an object capable of generating an event.

The Mouse object, for example, is automatically initialized with the AsBroadcaster object in Flash. It adds the addListener and removeListener methods to the Mouse object allowing you to add your own listeners and also runs broadcastMessage whenever you press, move, and/or release your mouse button. So if you click your mouse, Flash runs an internal

Mouse.broadcastMessage("onMouseDown");

and any listeners of the mouse object, like any movieclip for example (which is automatically made a listener of the Mouse object), will recognize the onMouseDown event and run any code they have associated with it.

Example 2
Now that we have a basic understanding of what AsBroadcaster does, ew can now use it to generate custom events from custom broadcaster objects for custom listeners to respond to. This example will still use the literal way of thinking as in Example 1, that being thinking of your listener objects as objects which are aware and listen for events to occur.

For this example I'm going to have to ask you step back in time a couple thousand years to the time of old where kings ruled and court jesters fooled. What we'll do here is make some new objects; a king and a royal subject, and use AsBroadcaster to control how they interact. The king, being a king, is going to give orders and our royal subject will listen for these orders and carry out a certain action when received. So in this example we have to first create our objects and assign them their traits/abilities. The king, for example, when we define him in actionscript as an object, will just be like every other object so we'll have to also make him a leader (using ASBroadcast.initialize) while our subject will have to be hired (using addListener) as a servant of the king and be given a job to do based on the commands given. Here's the code:

// a King is born!
King = {};
// our King is declared a leader
AsBroadcaster.initialize(King);

 
// a royal subject is born!
subject = {};
// our subject is now hired to listen to the king
King.addListener(subject);

 
// now we tell our subject his job
subject.onKingScream = function(){
trace("brings grapes");
}

 
// here we just make the King scream twice
// just for the heck of it ;)
King.broadcastMessage("onKingScream");
King.broadcastMessage("onKingScream");

When the King broadcasts his screams, the royal subject, as a listener, hears the screams and runs the onKingScream function its been assigned. This is the same thing which happens if you defined an onMouseDown event for a movieclip. When the mouse broadcasts the onMouseDown event, the movieclip runs its onMouseDown function. Here we are just using our King to broadcast the event and the subject object to listen and respond to that event. Any object you make can be used as a broadcaster broadcasting any event you want it to. You can even make predefined objects broadcast new custom methods as well, which brings us to Example 3.

Example 3
This quick example adds broadcaster functionality to a predefined actionscript object. This uses the Math object and a movieclip called ball_mc. Lets take a look:
 

// initialize Math object to be a broadcaster
AsBroadcaster.initialize(Math);

 
// create a new function for the Math object which
// returns the sum of two numbers. Included is the
// broadcasted onSum event
Math.sum = function(a,b){
this.broadcastMessage("onSum");
return a+b;
}

 
// make the ball_mc movieclip a listener of the Math object
Math.addListener(ball_mc);

 
// sets the ball_mc to to goto and play frame 2 whenever
// the onSum event occurs (called when ever Math.sum is run)
ball_mc.onSum = function(){
this.gotoAndPlay(2);
}

Now, whenever Math.sum is used on anything, anywhere in Flash, the ball_mc goes to and plays its frame 2.

How AsBroadcaster Really Works
How exactly does this generic object AsBroadcaster add this wonderful functionality to another object anyway? Its no secret. Its not even that hard to understand or even do without the AsBroadcaster object itself. All AsBroadcaster.intialize does to an object is add to it an array called _listeners and gives it some new methods to control the objects placed in this array. addListener adds an object in the array, removeListener removes one, and broadcastMessage runs, for each object in the _listeners array, a function with the same name as the passed string. In fact, though AsBroadcaster is a Flash MX object, its functionality can be implemented in Flash 5 all the same. The following code can be added to a Flash 5 movie to add custom AsBroadcaster functionality:
 

AsBroadcaster = new Object();
AsBroadcaster.addListener = function(listener){
this.removeListener(listener);
this._listeners.push(listener);
return true;
}
AsBroadcaster.removeListener = function(listener){
var i = this._listeners.length;
while(--i >= 0){
if(this._listeners[i] == listener){
this._listeners.splice(i,1);
return true;
}
}
return false;
}
AsBroadcaster.broadcastMessage = function(theEvent){
var i = this._listeners.length;
while(--i >= 0){
this._listeners[i][theEvent]();
}
}
AsBroadcaster.initialize = function(obj){
obj.addListener = this.addListener;
obj.removeListener = this.removeListener;
obj.broadcastMessage = this.broadcastMessage;
obj._listeners = [];
}

This creates the AsBroadcaster object and gives it the addListener, removeListener and broadcastMessage functions, which when initialize is called, gets passed down and copied to the initialized object. The object passed also gets the _listeners array which is used to hold all the listeners. The internal code use in Flash MX to define the AsBroadcaster object is very similar.

I said it adds "custom" AsBroadcaster functionality because using this in Flash 5 doesnt give you the full functionality of Flash MX. Yes you can create your own broadcaster objects and your own broadcast events, but it does not mean that your Mouse object will automatically start broadcasting the onMouseDown event when the mouse is pressed because, as it exists in Flash 5, the Mouse object doesnt know when that happens. Because of this, our Example 1 will not work in Flash 5, though Example 2 and 3 will.

Another difference with this example is that, here, for this Flash 5 version, you can't pass arguments into broadcastMessage to be received by your listeners. In MX you are able to pass any number of arguments after the event parameter in a broadcastMessage call to have those arguments passed to the listeners' call of that event. An example of this is in the Appendix below. Flash 5 just doesn't have the capability to make this possible because it cant parse the arguments followed by the event passed into the broadcastMessage call. In MX this would be achieved with the Function.apply method.

Broadcaster as List Holder
With this new attained knowledge of how AsBroadcaster really works, you can see that listener objects are, themselves, not altered in any way when they become a listener. This kind of contradicts the whole perception of these objects having gained this new ability of listening. In fact, all that happens is the broadcaster object is given a reference to that listener object and then is able to run any method of that listener it desires whenever it wants to (assuming the method exists). Alone, the listener object has no way of losing its listening ability unless the broadcaster itself is told to delete the listener out of the _listeners array using removeListener.

With that in mind, try instead not to think of listeners as listeners but just plain ordinary objects out off in the world somewhere. They mind their own business and you dont have to worry about them, what they can do or what they know, just that they exist. Now consider the broadcast object. This guy really is the head object in charge. He controls the commands and holds the list that says which one of those ordinary objects out there he can give these commands to. Any object on that list he can give commands to, an those objects, as long as they can recognize the command given, will have to do whatever the broadcaster object says; just because that's just the way it is. And that is how it is in Flash.

Example 4
This example I think embodies that train of thinking with the broadcaster being in charge. Here, the broadcaster will be the all mighty Santa Clause, because, after all, he has the power to control the happiness of all the children (and even many of the adults) of this world. Santa, as we all know, has his naughty and nice lists and depending on who is naughty and who is nice, Santa shall decide the fate of their happiness. What we'll do here is add people to the nice list and give anyone on it a present!

The example itself is structured much like Example 2, though there are some added elements and the AsBroadcaster object is renamed to cohere more to the Santa Clause metaphor. Here it is (note: some OOP used but the code sample is more to get an idea of how AsBroadcaster operates and a totally complete understanding isn't necessary)

// metaphor definitions - just to make things sound right
// person class to make Person objects
Person = function(name){
this.name=name;
}

 
// important person class to make ImportantPerson objects
ImportantPerson = function(name){
super(name);
}
// important person is a subclass of person
ImportantPerson.prototype = new Person();
// rename addListener
ImportantPerson.prototype.addToNiceList = function(n){
this.addListener(n);
}
// rename broadcastMessage
ImportantPerson.prototype.ForAllOnList = function(n){
this.broadcastMessage(n);
}
// traces the _listeners array
ImportantPerson.prototype.ReadNiceList = function(){
for(all in this._listeners){
trace(this._listeners[all].name);
}
}

 
// rename AsBroadcaster object
NiceList = AsBroadcaster;
// rename initialize object
AsBroadcaster.giveTo = AsBroadcaster.initialize;
// end definitions

 
// make Santa do his thing
SantaClause = new ImportantPerson("Santa Clause");
NiceList.giveTo(SantaClause);

 
Tommy = new Person("Tommy");
Tommy.givePresent = function(){
trace(this.name + " jumps for joy!");
};
Sarah = new Person("Sarah");
Sarah.givePresent = function(){
trace(this.name + " says, 'Thanky Santy!'");
};
Trevor = new Person("Trevor");
Trevor.givePresent = function(){
trace(this.name + " thinks, 'But Ive been naughty!?!'");
};

 
SantaClause.addToNiceList(Tommy);
SantaClause.addToNiceList(Sarah);

 
trace("Who's on the Nice List?\n-------------------");
SantaClause.ReadNiceList();

 
trace("\nGive Nice People Presents!\n-------------------");
SantaClause.ForAllOnList("givePresent");

When run, this code traces both Tommy's and Sarah's givePresent functions, but poor little Trevor, because he was naughty and not added to the nice list, recieved no present.

Advantages
It's important to note why you would want to use AsBroadcaster. At first it may seem overly complicated, but it does add an 'easier' method of interfacing with multiple class instances. More importantly, however, is that, despite the fact that AsBroadcaster really isn't anything completely new (as you saw a Flash 5 implementation was created and as I have mentioned, you have probably done something similar in the past), broadcastMessage is a great deal faster in looping through listeners than a normal actionscripted loop is. In fact, using AsBroadcaster can cut loop time by about half! This is because broadcastMessage uses an internal loop mechanism, ASnative(101, 12), to loop through the listeners array which is much faster than the loops produced by Actionscript.

Conclusion
As you can see, the AsBroadcaster object and the use of listeners adds a whole new perspective in how you can program your Flash applications. Though maybe not a new function of Flash it may change the way you'll want to handle and recognize events as they occur within Actionscript. Now you can have multiple objects in a scene all react to a broadcasted "onEarthquake" event with little effort and much speed.

Senocular

 


Some AsBroadcaster related scripts:

/* give all movieclips ability to broadcast */
AsBroadcaster.initialize(MovieClip.prototype);


 

/* broadcast event only to movieclips in a listeners list */
initiatedBroadcastObject.broadcastToMovies = function(theEvent){
var i = this._listeners.length
while(--i >= 0){
if(typeof(this._listeners[i]) == "movieclip"){
this._listeners[i][theEvent]();
}
}
}


 

/* send variables through a broadcasted event */
listenerObj.onEvent = function(argument){
trace("listenerObj recieved " + argument);
}
initiatedBroadcastObject.broadCastMessage("onEvent", "passed variable");
// traces "listenerObj recieved passed variable"


 

/* make an object listen to multiple broadcasters at once */
Object.prototype.listenTo = function(objs){
var i = 0, l = arguments.length;
for (i=0; i<l; i++){
if (!arguments[i].addListener) AsBroadcaster.initialize(arguments[i]);
arguments[i].addListener(this);
}
}


 

/* determines if an object is a broadcaster with listeners */
Object.prototype.isBroadcaster = function(){
return (this._listeners.length) ? true : false;
}


 

 

 




SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.