"BX" - My hobby AS3 framework
DIGG IT!
12
Comments
Published
Thursday, September 04, 2008
at
8:42 PM
.
Now that I have entered the world of management I have been feeling a bit lost without a project to code on as a hobby. For the past 2 years at Adobe I have been thinking about a simple light framework for building apps using XML/AS3. Whether it turns into anything or just a big pile of experiments, who knows. The plan is to dedicate evening time to "BX" and blog about my finding regardless of where they go. The first stop for "BX" is looking at events and rethinking them.
"BX":Events
------------------
About 6 months ago I ran some tests with the event model in FP9 and did a little proof on the scalability of various event models. In FP9 DOM level 2 events were added and these events provide the benefit of propagating across the display list from root to target and back. Now events are powerful things but if you get to many of them in your app or framework things can become hard to manage and ideally you want to have as few events subscribed as possible. So in "BX" I want to implement events differently and provide a bit more flexibility and allow name based events and system level events like so:
//name based events
import brix.Surface
class MyButton extends Surface{
function MyButton():void {
this.events.click = this.upClick; //event wiring
}
function upClick( event:Event ){ trace('upClick');}
}
or
//system level events
bx.events.click.push( myInstance.upClick );
bx.events.doubleclick.push( myInstance.upClick );
Notice addEventListener is never used. If you compiled this to a SWF and clicked on this an instance it would fire the click event. The "BX" framework simply handles dispathing the events directly, no muss or fuss. So then I got to thinking about bubbling and whether it was really necessary. I know I survived 6 years without it and looking back at the majority of my FX apps I never really leveraged bubbling or capture. I am going to leave it out for now, maybe a good use case will hit the project and I will add it in later.
So how is this possible, well the base class using "BX" has several event listeners that catch events when they are dispatched at the root in capture phase. The trick is that they are immediately canceled and use the event object passed to dispatch an event directly. Basically this short circuits the system and passes the event direct to the target. Where the player might waste time walking the display list, "BX" simply skips to the target. What I like is that regardless of how deeply nested the target it, the event always hits its target first without any walking or time wasted. I say this with a word of caution, this is a hack and although it speeds things up and simplifies how events work, the loss of DOM level 2 behavior a one way trip (but I could reverse that later). Instead of tracking who is subscribed to what, I simply change the names of the events and am able to rewire everything quickly with simple property changes.
I am seeing an issue with needing to fire 1+n things with a single event but this seems easy to solve as well. The event dispatcher here is simply calling a function and passing a single argument. So at runtime I can detect if it is an Array/Object and do something different like walk the Array dispatching events or simply call it if it is a function instance. This also allows you to chain events or dispatch events to a parent. With closure support in as3 I can set events to functions in other display objects and things just work without delegation.
There are some issues in terms of organizing events. I want to organize events into an object path for named events like so:
myInstance.events.click = this.myClick
The nice thing here is the ability to pass an entire events tree preconfigured. You might have 3 states within a component where events need to be shifted around and by simply swapping out the 'events' object you get sets of events to change all at once.
Well that is a long post for a single evening. I will keep blogging about "BX" and my progress. It should be a fun exploration into the unknown. Next time some code to munch on.
cheers,
Ted :)
Hi Ted,
Back in the AS2 days I had an even simpler approach. I used a static class that contained an Array of listeners/handlers. Events were both subscribed and dispatched though this static class so it was basically just 3 commands:
Events.sendEvent(eventName,paramObject);
Events.receiveEvent(eventName,handler);
Events.removeEvent(eventName,handler);
Using this approach, anything, anywhere in an app could send/receive events. Not only that - using this approach all the designers that I worked understood Events and that sure was a big bonus :)
Could this be an idea?
J
Jensa,
Indeed it nice and clean and might back sense in the system level events as an API.
I think the one element that I am striving for is listener discoverability/editability with simple properties. If you use methods to broker events the storage of the tree of listeners is masked/hidden. I would like developers to know what is subscribed by giving access to the event tree directly.
That said, this does make sense as an API for sending. Something like:
brix.system.events.send( eventName , obj );
myInstance.events.send( eventName , obj );
The global events mechanism reminds me of the 'notification' mechanism in PureMVC. Does this mean that you're not a real fan of a complete 'MVC' pattern but want to stick mostly to a global event mechanism (which I think might make sense in certain situations)? Do you happen to have any experience with Mate?
fyi re the name: there's an OSS project of the same name: http://code.google.com/p/brix-cms/
ria_flex,
The idea here is the make events simpler and easy to manager first. I dislike the forced use of addEventListener and some details of its implementation. It forces the developer to do alot of work to manage events and this could be far simpler. The complexity of events in FP9 (DOM Level 2) has been a steep learning curve for many.
As for MVC, sometimes obtaining global events is handy as is creating system managers to handle certain types of component behavior (overlays, pop-ups, windowing).
The question I have is which events take precedent, system events or instance events? My thought it to have 2 types of system events and sandwich instance events between. Like so:
1. Call brix.system.events.preclick
2. Call instance.events.click
3. Call brix.system.events.postclick
There are also some things you should only be able to do in system events, like frame or timer.
Ted :)
Michael,
Naming is always an issue these days. The BRIX I am working on is under BSD License. Who knows maybe I swap a letter somewhere.
ughhhh....
Ted :)
I'm sure FP9 events would have been a lot less problematic for a lot of people if they would have been weak references by default... I actually wonder how many developers realise that they the current strong references are a major cause of memory leaks...
@ria_flex: Clearly not enough. Events can be very hard to manage and can leak. The burden is on the developer to reference count and with the existing event API, you have no idea what is subscribed.
By making forcing event management to properties, these issues evaporate. Then you just need to worry about references.
Who knows under this design I could hit another wall. Again this is really a hobby framework and mainly an exploration into the unknown.
Ted :)
*** CONSPIRACY THEORY****
I hope you all are refactoring how events are used in AS, and this exercise is to feel how people would react to it.....
cause it COULD be so much more... direct.... ( pureMVC, Mate' )
This is no conspiracy, just me, AS3, and evening times.
And no the framework isn't yet another MVC framework.
:)
Im not focussed on the MVC, more interested in the way that the frameworks pass around events -
****see objective c****
Yeah I hear your pain, been more managing lately as well, so missing some of the quality time with AS3.
I've used a static message bus or overriding dispatchEvent for similar shortcutting, in a pinch any display object, e.g. stage can be used as a bus.
I actually really like the bubbling as a way to decouple controller from view.
http://troyworks.com/blog/2008/07/18/flash-working-with-events-get-on-the-busbubbling-is-your-friend/
I agree that the addEventListener is often more work, my approach is different, in that I have a FlowControl class that watches for clips to be added to the stage with defined patterns eg. (gotoAndPlay_frameLabel) that turns into addEventListener(CLICK, gotoAndPlay(frameLabel)). Freeing up designers to be non-scripters.
http://troyworks.com/blog/2008/07/22/flash-fast-prototyping-and-sketching-ui-with-flowcontrol/