Since the release of Flex 4 and the Spark framework, quite a lot has changed in the component life cycle. Not that this logic has been removed, it has just been added to to accommodate the new Spark framework. Hopefully I will find some time to update this or make a new post.
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
- 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.
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.