Filed under: actionScript, cairngorm, development, flex, frameworks | Tags: actionScript, cairngorm, development, flex, Maté, PureMVC, tips
So I am on the quest to create a hybrid MVC mini-framework that combines some of the best elements of Cairngorm, PureMVC and Maté. The idea is to use the Command pattern from Cairngorm (because I like all my service/UX logic to be placed there and the EventMap’s dependencies on binding and MXML seem limiting), the Mediator pattern from PureMVC (which unclutters and decouples the views) and the EventMap and Injection logic from Maté (which will help to further decouple some of the command=>model logic).
Keep in mind I have only really been working with Maté for a couple of months and have only dived into actually understanding it in the last week or so. So if you know of a better way of doing what I am trying to accomplish, please let me know and I can update the article.
This will mostly address how to decouple some of that command => model logic. This means we are striving to get the command classes as model-agnostic as possible. It also means there needs to be a slight modification to the current CairngormCommand structure. We will keep the CairngormEvent in use because its data payload is useful in sending data back and forth from the event dispatchers/listeners. In order for a command to send info back to a listener, it will need to extend EventDispatcher. Then depending on the result or fault logic, it can dispatch an appropriate event with a data payload. Here is some stub code:
public class SampleMateFriendlyCommand extends EventDispatcher implements IResponder
{
public function execute (evt:Event):void
{
//the function signature could be anything including execute (... args)
//notice I am not implementing the ICommand interface as I want to have more flexibility
}
public function result (data:Object):void
{
//parse data object if needed.
var evt:CairngormEvent = new CairngormEvent("success");
evt.data = parsedResultDataObject;
dispatchEvent(evt);
}
public function fault (info:Object):void
{
//parse info object if needed.
var evt:CairngormEvent = new CairngormEvent("fault");
evt.data = parsedFaultInfoObject;
dispatchEvent(evt);
}
}
I like the Command pattern because I think of it in a military sense. You issue a command to a soldier and that soldier executes the command, then generally reports back. So this is akin to that analogy. Next we need to see how to get the data back to the EventMap in order to wire the result/fault data into the appropriate places. I tinkered with this for quite some time before stumbling upon this solution. The Maté API docs are decent but fail to cover much beyond explaining the self explanatory. I really hope they work on their API docs and really flesh out the information.
<mate:EventHandlers id="applicationCompleteHandler" type="{AppEvent.SAMPLE_MATE_COMMAND}" debug="true">
<mate:AsyncCommandInvoker generator="{SampleMateFriendlyCommand}" successType="result">
<mate:successHandlers>
<mate:PropertySetter generator="{SomeModelObject}" targetKey="data" source="{scope.currentEvent.data}"/>
</mate:successHandlers>
</mate:AsyncCommandInvoker>
</mate:EventHandlers>
The AsyncCommandInvoker allows you to specify the event type that will trigger the successHandlers or the faultHandlers. Accessing the data payload for the result or success event is done using scope.currentEvent.data. Again I must reiterate that I stumbled upon this find because there was no documentation that I could find to support what I was trying to do.
The cool thing about this is that you have now freed up your commands so that they needn’t know about any specific model objects. That is unless you really want to strongly type your result data objects. This freedom allows for better testing as you can simply wire up a testing event map if you want to unit test.
Next up will be trying to wire mediators and their respective views into the event map.
Filed under: actionScript, components, development, flex, tutorial | Tags: actionScript, components, development, flex, mxml, tips
Assume that you are creating a component in MXML such as some multi-state cell renderer or something that implements IDataRenderer.
All mx.core.Container subclasses have a convenient little event hook called dataChange. Anytime you set a value to the data property, the component dispatches an event of type FlexEvent.DATA_CHANGE. To hook into this you simple access it in MXML like so:
<mx:VBox dataChange="do something"/>
With this in mind I suggest that those wishing to do more complex visual changes to their component that {binding} cannot address do the following:
- create a flag to indicate a data change has occured:
private var bDataChange:Boolean = false;
- connect the dataChange hook to the flag:
<mx:VBox dataChange="bDataChange = true;"/>
- address the data change in the call to update the display list:
override protected function updateDisplayList (unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); if (bDataChange) { bDataChange = false; //do your custom logic here } }
The nice bit about this is that you are doing the necessary logic to update the display list when it makes sense to do so (via the already established update framework in the Flex API). It also reduces the need to override the getter/setter for the data property.
Filed under: actionScript, client side, components, flex, jwo_lib, projects | Tags: actionScript, components, development, flex, jwolib, mxml
For those of you who use the Pod component I fixed the annoying issue of where title bar children’s visibile properties being set in MXML did not stick. Anyway revision 122 addresses this issue.
Filed under: actionScript, development, flash, flex, fun stuff, gaming, geometry, isolib, math, projects
I have used this blog to post most of the updates regarding the as3isolib. I recently got another blog just for it now. So any future updates will be posted there, not here.
Filed under: actionScript, client side, components, development, flash, flex, jwo_lib, mxml
A user of the lib brought to my attention a major flaw in my default styling setup. This new release address the default styling as well as a few things regarding the TileCanvas’s itemRenderer (IFactory) generator class (now can use UIComponent, should implement IDataRenderer for best use).
jwolib 2008.12.15 (includes src, asdocs & SWC) – link
Filed under: actionScript, client side, components, development, flex, fun stuff, gaming, isolib, projects, tutorial
The title sums it up – link
Filed under: actionScript, client side, components, development, flash, fun stuff, gaming, isolib, projects
This release addresses the issues associated with having a large number of scene items that might reside outside of the viewing area. Also incorporated includeInLayout implementation for IsoContainer objects and renamed a few classes/APIs.
Filed under: actionScript, components, development, flash, flex, tutorial
Reality Check
I have been developing in Flash for more years than I can remember and Flex since its inception. Its amazing how with that many years under my belt, a professional title of “Sr. Flex Consultant” and a pretty good comprehension of the “engine” of AS3, I still don’t know some basic things.
Case in point:
I was browsing Kirupa’s AS3 forums to see if I could swing in and make someone’s day by solving their AS3 woes. I found a guy who was basically trying to access child DisplayObjects on a DisplayObjectContainer from within the parent’s constructor. Now I don’t know if he was trying to access children instantiated programmatically or those placed on the timeline (I assume the latter case), but the problem is a result of the child references being null during the constructor. Seems like an easy solution right? Just wait and then do a check then any subsequent logic if applicable, else wait some more.
I wanted to provide the guy some insight and so I thought, “you know a UIComponent is pretty damn straight forward”. It even has a great method called childrenCreated that you can leverage. But trying to find a solution from a UIComponent is quite difficult because the process isn’t as straight forward as I had assumed it to be. I was amazed to realize that I hadn’t the clear understanding of what goes on under the hood of the MX framework as I had previously thought. Anyway, to make a not so long story short, I present a detailed look into the life of a UIComponent. BTW – all of this material can be found in the API docs as well as snooping around the MX code base.
Life of a UIComponent
Birth
- instantiation (aka. the constructor) – so there are a few differences when instantiating programmatically vs. declaritively (via MXML). For now let’s make the assumption that we are dealing with programmatic instantiation. The UIComponent doesn’t belong to the displayList, it is simply an object in memory.
- configuration – this may happen in the constructor or it may happen immediately after the UIC is created, but most properties needing initialization are set here as well as event handlers and other logic. Keep in mind that some properties that are actual getters/setters can flag the UIC for invalidation/validation logic.
- adding to the displayList – in order to be a useful UIC, it needs to be brought into the fold. So a parent UIC adds it to its displayList node. Interestingly, the addng of a UIC to the displayList causes a lot of under-the-hood logic to take place. For this section, the UIC in question is the one being added, not the parent.
- any former parent reference is removed (via DisplayObjectContainer(formerParent).removeChild(this))
- the UIC has some initialization performed on it regarding its document properties, styling, and some Module logic with regards to its new position within the displayList.
- the UIC is actaully added into the displayList. This is done at a lower level withing the Flash player. Doing so triggers an Event.ADDED event which is captured by the UIC’s parent. This event is delayed and redispatched at a later point.
- the UIC’s initialize() method is called which drills down yet another chain of events:
- initialization – the UIC’s initialize() method is called which drills down yet another logic chain. Note the possible recursive nature of this logic:
- the FlexEvent.PREINITIALIZE event is dispatched
- createChildren() is called
- childrenCreated() is called which trigger the invalidateProperties, …Size() and ..DisplayLIst() methods. Note that the UIC may have been flagged for invalidation in step #2 (the configuration phase)
- accesssibilities are initialized
- the FlexEvent.INITIALIZE event is dispatched
Life within the display list
Up till now, the life of our UIC has been pretty easy to follow. It and it’s parent have done quite a bit during the birthing process. But now that the UIC has been flagged for invalidation, it gets a bit blurry.
- invalidation – most of the getters/setters in a UIComponent have some logic that says, “if the new value doesn’t = the old” then it is to invalidate the properties, size and/or displayList. Most folks who do any component development make a great deal of use of these invalidation methods. Most folks (like me) probably had assumed their wasn’t any logic that took place betw. invalidation and validation processes. Oh but there is.An invalidation method is quite simple, it check two things, does the UIC (UIComponent hereinafter) have a parent and has a global-level ILayoutManager exist. If both conditions are met, then the UIC hands itself over (as a parameter) to the ILayoutManager. By doing these two checks a Flex app can conserve processing resources in case the UIC doesn’t reside within the displayList. Why update something that isn’t visible to the user? It does get updated, it just doesn’t get validated.
- managing the layout – Even though the name implies just layout-related tasks, the LayoutManager handles task related to invalidateProperties, invalidateSize and invalidateDisplayList. By a system of boolean flags and queues, the LayoutManager goes thru the 3 pre-validation phases of telling each UIC in its queue. Does UIC#2241782 need its size or properties validated? Does UIC#99892 need to update its display list? This kind of logic takes place here. The queing mechanisms are complex and recursive so I won’t go into detail here, but suffice it to say works alot like a short-order cook.
The really interesting thing about the LayoutManager is that it is main engine that drives the MX framework. If any of you were ol’ Flash dev’rs and remember having to do onEnterFrame logic, this kind of logic is presented here but in very tricky fashion. LayoutManager actually has a UIC that doesn’t reside in the display list. This UIC is called the callLaterObject and as you can guess is used as the work horse for leveraging the ENTER_FRAME and RENDER events that get triggered. At each triggering, the callLaterObject then reports back to the LayoutManager that we are in the next frame so we can now start the validation process on our queued UICs.
- validation – now that we have a new frame to work with, the LayoutManager will goto its needs-validation-queue and grab each UIC and issue validation orders. Once that is done, the UIC in question gets added to yet another queue and a series of checks takes place before starting all over again for the next round of invalidation requests.
Summary
With the sort of logic that takes place for a mutltitude of UIComponents within an app, the geniuses over at Adobe have come up with a highly efficient system for managing resources while making the updates. I hope this provides some insight. And also sound off if you find that I am in error in writing this, as this was a journey of discovery for me as well.
J
Filed under: actionScript, development, flash, flex, fun stuff, music, projects
My buddy Mike Orth and I just wrapped up some pretty cool features for the MediaCoreLib. Rather than write something orignal, I will just steal some of what Mike wrote on his blog:
MediaCoreLib – Here’s an easy way to play rich media content (audio, video) inside Flash or Flex and manage it all in one place.
The new MediaCoreLib alpha release includes an extensive PlaylistManager as well as a merging of my FadingSound component to allow for crossfading between tracks. For a more info check out the Google code repository…..
His full post can be found here – link
MediaCoreLib project home – link
XFade adv. testing app – link
Please leave us some feedback and feature requests. We have some really neat features in store for the next release!
A buddy of mine asked me the other day if I had any thoughts on normalizing value objects coming in from various services. For example say you have at least 3 different objects that all share similar properties but aren’t quite named the same thing for convenience sake. Let’s assume that your service guy is simply assembling objects straight from the database table and using their column names rather than normalizing it for you. Here are the sample objects:
ArtistObject
{
artistName:String
artistId:int
artistGenres:Array
}
AlbumObject
{
albumName:String
albumId:int
albumGenres:Array
}
TrackObject
{
trackName:String
trackId:int
trackGenres:Array
}
And let’s say you want to normalize those incoming objects to an interface like so:
IMediaObject
{
name:String
id:int
genres:Array
}
Your first inclination may be to use an else..if statement to cycle thru the variou value object types that may be expected in a given response (assuming you are not doing low-level CRUD services and are actually leveraging services for various purposes) like so:
if (vo is ArtistObject)
{ ... }
else if (vo is AlbumObject)
{ ... }
else if (vo is TrackObject)
{ ... }
else if .... you get the point
Here is an often overlooked but extremely useful operation that will eliminate lengthy else..if loops while allowing you to cycle thru known properties to retrieve non-normalized property values.
var targetObject:IMediaObject = //whatever you are normalizing to
var vo:Object = serviceResponse.data //the object returned from your service
for (var s:String in vo)
{
//we are going to check each prop name to see if there is a match for our
//targetObject's known properties
//obviously this list will grow the more props you have to normalize
//however it only grows once regardless of the number of non-normalized VOs
if (s.toLowerCase().indexOf('name') != -1)
targetObject.name = String(vo[s]);
if (s.toLowerCase().indexOf('id') != -1)
targetObject.id = int(vo[s]);
if (s.lowerCase().indexOf('genres') != -1)
targetObject.genres = vo[s] as Array;
}
