SlideShare ist ein Scribd-Unternehmen logo
1 von 76
Page 0 of 59 Flex 4 Components from the Fire Hose Michael Labriola Senior Consultants Digital Primates twitter.com/mlabriola
Who am I? Michael Labriola Senior Consultant Digital Primates Client side architect specializing in Adobe Flex Architect and developer of Fluint Lead architect and developer of FlexUnit 4.x Team Mentor Co-Author of Flex Training from the Source Series Geek Page 2 of 59
Pregame Pre-compile, compile and linking time 3
What are we going to cover? We are going to start with MXML  We are going to see what it looks like after it is compiled We are then going to walk through each class on the way from instantiation through display We will cover as much as we can before time runs out Page 3 of 59
Here is our source code Firehose.mxml is our main application file. It consists of the following pieces: <?xml version="1.0" encoding="utf-8"?> <s:Application  xmlns:fx="http://ns.adobe.com/mxml/2009"  xmlns:s="library://ns.adobe.com/flex/spark"> 	<s:Button id="btn" label="Click Me"/> </s:Application> Page 3 of 59
Generation This code turns into many generated files. Most important to us are: ActionScript version of your Application subclass ActionScript subclass of the system manager Getter/Setter generation for mxml properties Flex Init Mixin Styles, styles and more styles Page 3 of 59
Application Subclass The first piece of generated code is the Application subclass. When the application is subclassed, several important things occur: Frame metadata is specified Properties are created for MXML components in the document Factory functions are created for the MXML content The mxmlContentFactory is set Style declaration setup is deferred for a bit Page 3 of 59
Frame metadata Page 3 of 59 The following metadata is added to the application subclass: [Frame(extraClass="_Firehose_FlexInit")] [Frame(factoryClass="_Firehose_mx_managers_SystemManager")] The first line ensures the inclusion of the Firehose_FlexInitmixin The second line specifies that the Firehose_mx_managers_SystemManager is the bootstrapped root class for your swf
MXML Properties Page 3 of 59 A Bindable public property is created for the MXML instances so that you can refer to these by id in the Application [Bindable] public varbtn : spark.components.Button; Note this corresponds to the id of the object in the MXML <s:Button id="btn" label="Click Me"/>
Factory Functions Page 3 of 59 For each MXML tag, a factory function is created to build the corresponding object and set its properties private function _Firehose_Button1_i():Button { var temp : Button = new spark.components.Button(); temp.label = "Click Me"; 	temp.id = "btn"; 	if (!temp.document) temp.document = this; btn = temp; BindingManager.executeBindings(this, "btn", btn); 	return temp; }
Factory Functions Page 3 of 59 An Array of all of the components is then created invoking each of those methods and adding the result to the Array private function _Firehose_Array1_c() : Array { var temp : Array = [_Firehose_Button1_i()]; 	return temp; }
Multiple Controls Page 3 of 59 For example, if we had three buttons as peers, the code would like this: <s:Button id="btn1" label="Click Me"/> <s:Button id="btn2" label="Click You"/> <s:Button id="btn3" label="Click It"/> private function _Firehose_Array1_c() : Array { var temp : Array = [_Firehose_Button1_i(), 					  _Firehose_Button2_i(), 				  _Firehose_Button3_i()]; 	return temp; }
Non Skinnable Page 3 of 59 Flex 4 is full of new classes to learn. Let’s start by discussing an old favorite, UIComponent and a new addition Group. UIComponent is still the base class of all components and containers in Flex 4.  Group is the base container class. It can hold an unknown number of elements which may be defined in MXML and is akin to a lighter-weight version of Container from the mx component set
Skinnable* Page 3 of 59 Two additional new classes in Flex 4 worth noting at this time: SkinnableComponent and SkinnableContainer The SkinnableComponent class is the base class for all components where the view has been separated from component logic through the use of a skin. It is a UIComponent subclass The SkinnableContainer class is a subclass of SkinnableComponent which allows for both a skin and unknown additional elements which may be defined in MXML
mxmlContentFactory Page 3 of 59 The goal of all of the work in the generated application code so far has been to set the mxmlContentFactory property of the Firehose class (Application subclass).  This property is defined in SkinnableContainer and allows us to specify those unknown MXML children. This property is typed as an IDeferredInstance. this.mxmlContentFactory =  	new DeferredInstanceFromFunction(_Firehose_Array1_c);
IDeferredInstance Page 3 of 59 To be an IDeferredInstance a class must have a single method: public function getInstance():Object { 	... 	return something; } An IDeferredInstance defers the creation of an object until its getInstance() method is called. Each subsequent call returns the originally created instance
DeferredInstanceFromFunction Page 3 of 59 Our generated code is simply a function and the mxmlContentFactory expects the IDeferredInstance. The DeferredInstanceFromFunction handles this issue this.mxmlContentFactory =  	new DeferredInstanceFromFunction(_Firehose_Array1_c);  The DeferredInstanceFromFunction class takes a function as its first parameter. When its getInstance() method is called it invokes that method to create the component graph
Nested Controls Page 3 of 59 The factory functions generated change a bit when we have nested controls: <s:Button id="btn1" label="Click Me"/> <s:Group> 	<s:Button id="btn2" label="Click You"/> 	<s:Button id="btn3" label="Click It"/> </s:Group>
Nested Controls Generated Page 3 of 59 private function _Firehose_Array1_c() : Array { var temp : Array = [_Firehose_Button1_i(), 					  _Firehose_Group1_c()]; 	return temp; } private function _Firehose_Button1_i() : Button { ... } private function _Firehose_Group1_c() : Group { var temp : Group = Group(); temp.mxmlContent = [_Firehose_Button2_i(), 					  _Firehose_Button3_i()]; 	if (!temp.document) temp.document = this; 	return temp; }
Nested Group Page 3 of 59 In the case of the nested group, you may notice that the mxmlContent property is set, instead of the mxmlContentFactory. var temp : Group = Group(); temp.mxmlContent = [_Firehose_Button2_i(), 		 		       _Firehose_Button3_i()]; Further, the property is set directly to the Array built by calling these methods. The mxmlContent property is the final home of all children. In this case they are created immediately instead of deferred
Application Subclass The next major piece of generated code is the SystemManager subclass. Several important things occur here: The subclass implements IFlexModuleFactory The subclass implements ISWFContext The create() method is overridden The info() method is overridden Page 3 of 59
IFlexModuleFactory Page 3 of 59 The newly created SystemManager subclass will implement IFlexModuleFactory and ISWFContext which requires a number of interesting methods. The most interesting ones to us at this moment are: function registerImplementation(interfaceName:String, 					impl:Object):void; function getImplementation(interfaceName:String):Object; function create(... parameters):Object; function info():Object;
registerImplementation() Page 3 of 59 This method allows the Flex framework, and you should you wish, to register Singletons that implement a specific interface. It is sort of a Dependency Injection registration meets singleton and had a baby scenario: public function registerImplementation(interfaceName:String, impl:Object):void; You call this method with an interface you wish to register and an implementing object.
getImplementation() Page 3 of 59 This method allows you to getImplementations that were previously registered. So, for example, if you wanted to register a given singleton you could then later retrieve it through the SystemManager public function getImplementation(interfaceName:String):Object
create() Page 3 of 59 The create() method is where the magic happens and your app will be instantiated: override public function create(... params):Object { 	... varmainClassName:String =  params.length == 0?"Firehose“:String(params[0]); varmainClass:Class = 					Class(getDefinitionByName(mainClassName));    if (!mainClass) return null; varinstance:Object = new mainClass();    if (instance is IFlexModule)      (IFlexModule(instance)).moduleFactory = this;       return instance; }
info() Page 3 of 59 The info() method returns a generic object filled with required and optional properties used to configure the system.  Examples of data you may find in the object returned by info(): 	RSL data, compiled locales, resource bundle names, application domain, main class name, mixins and the correct preloader to use
info() Page 3 of 59 In this code snippet from info() you can see where the mixins are specified. This is the way in which Flex applies some of the additional generated code to the system manager. _info = {   … mainClassName: "Firehose", mixins: [ "_Firehose_FlexInit", "_Firehose_Styles" ], preloader: mx.preloaders.SparkDownloadProgressBar }
Mixin Page 3 of 59 Mixin classes are decorated with the Mixin metadata and have a public static method named init() that takes a IFlexModuleFactory (SystemManager in this case) as an argument.  The mixin effectively sets properties and instances on the SystemManager to create the StyleManager, register styles and more
Btn Binding Setup Page 3 of 59 Earlier I mentioned that Flex creates a public var for btn on the host component because we have an MXML control named btn. That was true then. However, this is Flex, and in Flex all MXML components are bindable, therefore, that public var actually becomes a getter and setter before we are done
Btn Binding Setup Page 3 of 59 [Bindable(event="propertyChange")] public function get btn():spark.components.Button { 	return this._97884btn; } public function set btn(value:spark.components.Button):void{ varoldValue:Object = this._97884btn; 	if (oldValue !== value) { 		this._97884btn = value; 		if (this.hasEventListener("propertyChange")) this.dispatchEvent( 					         PropertyChangeEvent.createUpdateEvent( 				this, "btn", oldValue, value));    } }
Watcher Setup Page 3 of 59 If you add one Bindable properties to your application. You receive the following additons, which is the code watching for Bindable changes.  <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"  xmlns:s="library://ns.adobe.com/flex/spark"> 	<fx:Script> <![CDATA[ 			[Bindable] 			public varlblMe:String; 	]]> 	</fx:Script> 	<s:Button id="btn" label="{lblMe}"/> </s:Application>
lblMe Binding Setup Page 3 of 59 private function _Firehose_bindingsSetup():Array { varresult:Array = [];         result[0] = new mx.binding.Binding(this,             null,             null,             "btn.label"             , "lblMe");         return result; }
lblMe Watcher Setup Page 3 of 59 public function setup(target:Object, propertyGetter:Function, staticPropertyGetter:Function, bindings:Array, watchers:Array):void { 	watchers[0] = new mx.binding.PropertyWatcher("lblMe", 				{propertyChange: true },         		[bindings[0]], propertyGetter ); 	watchers[0].updateParent(target); }     } }
Application Constructor Page 3 of 59 if (_watcherSetupUtil == null) { varwatcherSetupUtilClass:Object = 	getDefinitionByName("_FirehoseWatcherSetupUtil"); watcherSetupUtilClass["init"](null); } _watcherSetupUtil.setup(this, function(propertyName:String):*  		{ return target[propertyName]; }, function(propertyName:String):*  		{ return Firehose[propertyName]; }, 		bindings, watchers); mx_internal::_bindings = mx_internal::_bindings.concat(bindings); mx_internal::_watchers = mx_internal::_watchers.concat(watchers); for (var i:uint = 0; i < bindings.length; i++) { 	Binding(bindings[i]).execute(); }
GAME TIME Loading and Running 35
SWF Load Page 3 of 59 You begin loading your SWF into the browser of your choice. However, you need to remember that SWF is a streaming format, so it arrives a frame at a time. Thanks to your frame metadata, you already told the SWF it should instantiate your SystemManager… so it does.
SystemManager Constructor Page 3 of 59 The SystemManager’s constructor is called where it does a few things like figure out if it is the top level or if it has been loaded into another SWF. If it is the top, it sets alignments and scale modes on the stage and then does something extremely important: stop(); We need to wait until we have loaded everything we need before we advance to the next frame and start the application
SystemManager Constructor Page 3 of 59 The final line in the SystemManager’s Constructor: if (root && root.loaderInfo) root.loaderInfo.addEventListener(Event.INIT, initHandler); It waits until an INIT event is broadcast from the loaderInfo object. This event is broadcast the moment once everything needed by this first frame is available and the SystemManager’sConnstructor finishes
init() Page 3 of 59 One the initHandler() is called, the world gets more interesting.  This method does a little cleanup, removes the existing init event listener and some other pieces, however, the two critical things it does for this presentation: Adds another event listener for a method named docFrameListener which is called when the rest of the application is loaded Calls the initialize() method
initialize() Page 3 of 59 This method is responsible for creating the PreLoader. The PreLoader itself is a logical class, but it allows us to specify a display class which is displayed to the user to make a better user experience while we load the remainder of the app. This method also starts downloading any RSLs needed for your application… and some it doesn’t need Then we wait until the all of the RSLs are loaded and the remainder of the app is loaded
kickOff() Page 3 of 59 When both of these conditions are true (and they can happen in any order) either the preloader or the docFrameHandler catches this fact and ensures kickOff() is called. This method registers a ton of classes as singletons to support everything from fonts to drag and drop. It also instantiates all of those mixins we discussed in the pregame, adding those pieces to the system manager at this time
initializeTopLevelWindow() Page 3 of 59 This method does a lot of work to ensure we load correctly and size appropriately, however, the part that interests us most: childManager.initializeTopLevelWindow(w, h); ChildManager is an instance of a class that implements ISystemManagerChildManager, meaning that it has methods to handle the result of adding and removing children as well as the initialize method we call here. In this case, it is an instance of ChildManager
ChildManager() Page 3 of 59 Inside of ChildManager, the create() method that was overridden by the compiler is called, effectively creating the instance of your application. A creationComplete event handler is added to the application and the preloader is informed of the application’s existence so that it may leave gracefully when the application is ready Note, the application is created but not yet added to the System Manager… that will happen much later
ChildManager() cont Page 3 of 59 Inside of the ChildManager, the addingChild() method is called. This method sets the nestLevel for the new component (nestLevel increase as depth of the component increases) The childAdded() method is called next, which dispatches an ADD event for the child and calls the child’s initialize… And the fun begins
PreInitialize Page 3 of 59 The Application initializes several managers and the context menus before beginning the component initialization cycle. This starts by broadcasting FlexEvent.PREINITIALIZE. This is one of the most important events in all of Flex.  It means the display object dispatching is initialized, however, it has yet to create any of its visual children. Anything that you want to do which will affect the number or type of children should be done NOW
createChildren() Page 3 of 59 Immediately after dispatching the event, the createChildren() method is called. The createChildren() method is responsible for creating all relatively static visual children of a component.  In non-skinnable components this method created all visual children directly. In skinnable components, this method invokes validateSkinChange() (which is invoked now and when the skin changes at runtime)
validateSkinChange() Page 3 of 59 The validateSkinChange() checks for an existing skin and detaches it if it exists. It then performs the most important operation here, it calls attachSkin() .. 	if (skin) detachSkin(); attachSkin(); ..
attachSkin() Page 3 of 59 The attachSkin() method finds the correct skin for this component, instantiates it, and passes the result to the setSkin() method. In our application, this means creating an instance of the ApplicationSkin. ApplicationSkin is a Skin, which is just a Group and ultimately a UIComponent, so it will have this same life cycle recursively. The setSkin() method sets the _skin property of the class and dispatches a skinChanged event
attachSkin() Page 3 of 59 At this point, the owner and hostComponent of the skin are set. The hostComponent of a skin always refers to the object for which it is providing a visual display. Note, not the hostComponent and owner property is set after the class skin instantiated. You cannot access either of these properties during the skin’s construction
attachSkin() Page 3 of 59 After the skin is created, the styles of the component are passed to the skin for use. At this point, the skin is added to the component, kicking off its life cycle. The addingChild() method is called, followed by actually adding it via the player APIs. Then the childAdded() method is called. The childAdded method, much like it did for the application, causes the ApplicationSkin’s initialize method to be called
Skin PreInitialize Page 3 of 59 The skin now broadcasts its FlexEvent.PREINITIALIZE.  It means the skin is initialized, however, it has yet to create any of its visual children.  I reiterate, Anything that you want to do which will affect the number or type of children should be done NOW
Skin createChildren() Page 3 of 59 Immediately after dispatching the event, the createChildren() method is called.  Within the skin, the setMXMLContent method is called. This method takes an array of MXML objects defined in the skin (much like the array you saw in the nested example). All old MXML elements are removed from the skin, and add all of the new elements, using a method named addElement()
addElement() Page 3 of 59 Immediately after dispatching the event, the createChildren() method is called.  Within the skin, the setMXMLContent method is called. This method takes an array of MXML objects defined in the skin (much like the array you saw in the nested example). All old MXML elements are removed from the skin, and add all of the new elements. We use the word element here as the items we are adding or removing are of type IVisualElement
IVisualElement Page 3 of 59 IVisualElement is a new interface to spark which defines the properties that must be present on an object to be correctly sized, positioned and displayed in any type of spark container In spark, controls, containers and even graphic primitives can be IVisualElements. Using this interface is a key component to allowing spark to intermingle these classes
elementAdded() cont Page 3 of 59 As the new visual elements are added to the skin, the skin’s elementAdded() method is called. In this method, the elementAdded method of the layout object is also called to inform it of a change, and the invalidateLayering() method is called to inform the skin that the layering of objects may have changed.  This invalidation eventually leads to a call to assignDisplayObjects() which reorders the objects
elementAdded() Page 3 of 59 In the case where the element is an IGraphicalElement (an interface that descends from IVisualElement to specifically handle the needs of graphics) a special method called addingGraphicalElement() is called and passed the element. IGraphicalElements are not displayObjects on their own like components. They are simply logic and state which draw onto a display object. This means that Flex must identify the correct display object for drawing.
elementAdded() Page 3 of 59 In all other cases, the element is assumed to be a displayObject and added to the display list via a method named addObjectToDisplayList() This method ensures the child reaches the display list at the appropriate location Any listeners are notified of the fact that a new element was added and the invalidateDisplayList() and invalidateSize() methods are called to ensure the skin is sized and repositioned
More Recursion Page 3 of 59 The addition of each of these elements to the display list causes their initialize() methods to be called. They go through the same process of either instantiating components or instantiating skins, which then instantiate components, which may have skins, with components, with skins….
Back Up Page 3 of 59 Starting from the deepest point on the stack of children, each child does the following operations: invalidateProperties() invalidateSize() invalidateDisplayList() sets processedDescriptors = true dispatches its FlexEvent.INITIALIZE event
Child Additions Page 3 of 59 Starting from the deepest point on the stack of children, each children performs the following operations: invalidateProperties() invalidateSize() invalidateDisplayList() sets processedDescriptors = true dispatches its FlexEvent.INITIALIZE event
FlexEvent.INITIALIZE Page 3 of 59 The initialize event is always broadcast by the inner most child first. It signifies that all of the visual children have been created, however, the children nor the component have been sized or positioned at this time. This is a great place to make visual modifications to children.
findSkinParts() Page 3 of 59 After each skin initializes, you return to the attachSkin() method where the skin was first added. We now execute a method named findSkinParts(). This method looks through the SkinParts defined via the [SkinPart] metadata in any SkinnableComponent subclass.  If it finds an element with a matching id in the skin, it provided the variable annotated with the [SkinPart] metadata with a reference to that part in the skin
partAdded() Page 3 of 59 As each of these parts is identified and the reference provided, the partAdded() method of SkinnableComponent is called and provided both the string name of the skin part and a reference to it: if (this[id] != null && !(this[id] is IFactory)) partAdded(id, this[id]); It is common to override this method in your own components to configure each skin part as it is added. There is a parallel method called partRemoved() which is called with the same arguments if a part is removed.
partAdded() Page 3 of 59 The default behavior of the partAdded() method is to dispatch a SkinPartEvent.PART_ADDED event with the partName and instance which can also be used for configuration or other logic
SkinStates Page 3 of 59 After all parts are added, the invalidateSkinState() method is called. When you define a SkinnableComponent, you can specify required SkinStates that the skin must fulfill. Meaning it will have those states defined in the skin. [SkinState("up")] [SkinState("over")] --- --- --- --- --- --- <s:states>   <s:State name="up" />   <s:State name="over" /> </s:states>
SkinStates Page 3 of 59 The invalidateSkinState() method informs the component that the skin needs to know its new visual state As a result of this call, the getCurrentSkinState() method of this component will be called asynchronously. It is expected to return a string that matches one of those valid states It can derive this information in any way it chooses and is not bound to the component state
Deferred Page 3 of 59 After all of the skins are attached, the stack returns to the createChildren() method Here it calls a method named createDeferredContentIfNeeded() This method looks for any items specified in the mxmlContentFactory that have not yet been instantiated and creates them now… starting yet another recursive cycle. Note, this is where the Flex compiler assigned our original content
Deferred Creation Page 3 of 59 This means initialize is a bit trickier. Skins for a class are created before MXML content, so for instance the ApplicationSkin will be created well before the Button creation begins This is consistent with the use of initialize but, depending on the complexity of the skin may seem strange at first glance
Recursion Complete Page 3 of 59 One all of the children are initialized from the inner most to the outer, you will be able to finish the initialize() method of the Application that we started many slides ago. Now we need to worry about invalidation.
Invalidation Page 3 of 59 All of this invalidation effectively adds each of these components to a priority queue. This priority queue sorts based on the nestLevel that we mentioned earlier. As these queues are resolved the outer most item toward the deepest have their validateProperties() method called. Then the deepest moving toward the outermost have their validateSize() method called. Finally, from the outer toward deepest, the validateDisplayList() method is called
Invalidation Page 3 of 59 After each component has had a chance to complete all necessary validation, it is marked as initialized. Not this is different than the INITIALIZE event Marking a component as Initialized does two important things.  it sets the component to visible (if applicable) It dispatches a FlexEvent.CREATION_COMPLETE
creationComplete Page 3 of 59 The FlexEvent.CREATION_COMPLETE means that all layout, sizing and positioning is complete and the item can now be visible on the screen. It is just about the worst time to do anything, save for operations that need to know the size and position of a child
Application Visible Page 3 of 59 Once all of the children have broadcast their creationComplete event, the time for the application to complete is here The application broadcasts its creationComplete, which is a trigger to System Manager. The System Manager destroys the preloader and adds the Application as a child to the System Manager, making it visible.
Application Complete Page 3 of 59 The act of making the application a child of the system manager is among the last acts performed before the System Manager broadcasts a FlexEvent.APPLICATION_COMPLETE from the Application. This signals that the application is ready to be used.
Questions Page 3 of 59 ?
Page 59 of 59 Me Michael Labriola http://twitter.com/mlabriola

Weitere ähnliche Inhalte

Ähnlich wie Flex 4 Components

iPhone Seminar Part 2
iPhone Seminar Part 2iPhone Seminar Part 2
iPhone Seminar Part 2NAILBITER
 
An MXM-based Application for Sharing Protected Content
An MXM-based Application for Sharing Protected ContentAn MXM-based Application for Sharing Protected Content
An MXM-based Application for Sharing Protected ContentAlpen-Adria-Universität
 
matmultHomework3.pdfNames of Files to Submit matmult..docx
matmultHomework3.pdfNames of Files to Submit  matmult..docxmatmultHomework3.pdfNames of Files to Submit  matmult..docx
matmultHomework3.pdfNames of Files to Submit matmult..docxandreecapon
 
Android development training programme , Day 3
Android development training programme , Day 3Android development training programme , Day 3
Android development training programme , Day 3DHIRAJ PRAVIN
 
Flex Building User Interface Components
Flex Building User Interface ComponentsFlex Building User Interface Components
Flex Building User Interface ComponentsAhmad Hamid
 
WINDOWS ADMINISTRATION AND WORKING WITH OBJECTS : PowerShell ISE
WINDOWS ADMINISTRATION AND WORKING WITH OBJECTS : PowerShell ISEWINDOWS ADMINISTRATION AND WORKING WITH OBJECTS : PowerShell ISE
WINDOWS ADMINISTRATION AND WORKING WITH OBJECTS : PowerShell ISEHitesh Mohapatra
 
ActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsSaurabh Narula
 
EclipseCon 2009: TmL Tutorial Exercises
EclipseCon 2009: TmL Tutorial ExercisesEclipseCon 2009: TmL Tutorial Exercises
EclipseCon 2009: TmL Tutorial ExercisesEric Cloninger
 
Java: Inheritance
Java: InheritanceJava: Inheritance
Java: InheritanceTareq Hasan
 
Chap2 class,objects
Chap2 class,objectsChap2 class,objects
Chap2 class,objectsraksharao
 
New client side features - Microsoft Dynamics CRM 2016
New client side features - Microsoft Dynamics CRM 2016New client side features - Microsoft Dynamics CRM 2016
New client side features - Microsoft Dynamics CRM 2016Naveen Kumar
 

Ähnlich wie Flex 4 Components (20)

iPhone Seminar Part 2
iPhone Seminar Part 2iPhone Seminar Part 2
iPhone Seminar Part 2
 
An MXM-based Application for Sharing Protected Content
An MXM-based Application for Sharing Protected ContentAn MXM-based Application for Sharing Protected Content
An MXM-based Application for Sharing Protected Content
 
matmultHomework3.pdfNames of Files to Submit matmult..docx
matmultHomework3.pdfNames of Files to Submit  matmult..docxmatmultHomework3.pdfNames of Files to Submit  matmult..docx
matmultHomework3.pdfNames of Files to Submit matmult..docx
 
Android development training programme , Day 3
Android development training programme , Day 3Android development training programme , Day 3
Android development training programme , Day 3
 
Online CPP Homework Help
Online CPP Homework HelpOnline CPP Homework Help
Online CPP Homework Help
 
MS Access Macros
MS Access MacrosMS Access Macros
MS Access Macros
 
User defined functions in matlab
User defined functions in  matlabUser defined functions in  matlab
User defined functions in matlab
 
Flex Building User Interface Components
Flex Building User Interface ComponentsFlex Building User Interface Components
Flex Building User Interface Components
 
WINDOWS ADMINISTRATION AND WORKING WITH OBJECTS : PowerShell ISE
WINDOWS ADMINISTRATION AND WORKING WITH OBJECTS : PowerShell ISEWINDOWS ADMINISTRATION AND WORKING WITH OBJECTS : PowerShell ISE
WINDOWS ADMINISTRATION AND WORKING WITH OBJECTS : PowerShell ISE
 
Adobe Flex4
Adobe Flex4 Adobe Flex4
Adobe Flex4
 
Java scriptfunction
Java scriptfunctionJava scriptfunction
Java scriptfunction
 
Eclipse Tricks
Eclipse TricksEclipse Tricks
Eclipse Tricks
 
ActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsActionScript 3.0 Fundamentals
ActionScript 3.0 Fundamentals
 
EclipseCon 2009: TmL Tutorial Exercises
EclipseCon 2009: TmL Tutorial ExercisesEclipseCon 2009: TmL Tutorial Exercises
EclipseCon 2009: TmL Tutorial Exercises
 
Java: Inheritance
Java: InheritanceJava: Inheritance
Java: Inheritance
 
Chap2 class,objects
Chap2 class,objectsChap2 class,objects
Chap2 class,objects
 
XAML and WPF - Dinko Jakovljević
XAML and WPF - Dinko JakovljevićXAML and WPF - Dinko Jakovljević
XAML and WPF - Dinko Jakovljević
 
New client side features - Microsoft Dynamics CRM 2016
New client side features - Microsoft Dynamics CRM 2016New client side features - Microsoft Dynamics CRM 2016
New client side features - Microsoft Dynamics CRM 2016
 
Vb.net iv
Vb.net ivVb.net iv
Vb.net iv
 
Intake 38 4
Intake 38 4Intake 38 4
Intake 38 4
 

Flex 4 Components

  • 1. Page 0 of 59 Flex 4 Components from the Fire Hose Michael Labriola Senior Consultants Digital Primates twitter.com/mlabriola
  • 2. Who am I? Michael Labriola Senior Consultant Digital Primates Client side architect specializing in Adobe Flex Architect and developer of Fluint Lead architect and developer of FlexUnit 4.x Team Mentor Co-Author of Flex Training from the Source Series Geek Page 2 of 59
  • 3. Pregame Pre-compile, compile and linking time 3
  • 4. What are we going to cover? We are going to start with MXML We are going to see what it looks like after it is compiled We are then going to walk through each class on the way from instantiation through display We will cover as much as we can before time runs out Page 3 of 59
  • 5. Here is our source code Firehose.mxml is our main application file. It consists of the following pieces: <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"> <s:Button id="btn" label="Click Me"/> </s:Application> Page 3 of 59
  • 6. Generation This code turns into many generated files. Most important to us are: ActionScript version of your Application subclass ActionScript subclass of the system manager Getter/Setter generation for mxml properties Flex Init Mixin Styles, styles and more styles Page 3 of 59
  • 7. Application Subclass The first piece of generated code is the Application subclass. When the application is subclassed, several important things occur: Frame metadata is specified Properties are created for MXML components in the document Factory functions are created for the MXML content The mxmlContentFactory is set Style declaration setup is deferred for a bit Page 3 of 59
  • 8. Frame metadata Page 3 of 59 The following metadata is added to the application subclass: [Frame(extraClass="_Firehose_FlexInit")] [Frame(factoryClass="_Firehose_mx_managers_SystemManager")] The first line ensures the inclusion of the Firehose_FlexInitmixin The second line specifies that the Firehose_mx_managers_SystemManager is the bootstrapped root class for your swf
  • 9. MXML Properties Page 3 of 59 A Bindable public property is created for the MXML instances so that you can refer to these by id in the Application [Bindable] public varbtn : spark.components.Button; Note this corresponds to the id of the object in the MXML <s:Button id="btn" label="Click Me"/>
  • 10. Factory Functions Page 3 of 59 For each MXML tag, a factory function is created to build the corresponding object and set its properties private function _Firehose_Button1_i():Button { var temp : Button = new spark.components.Button(); temp.label = "Click Me"; temp.id = "btn"; if (!temp.document) temp.document = this; btn = temp; BindingManager.executeBindings(this, "btn", btn); return temp; }
  • 11. Factory Functions Page 3 of 59 An Array of all of the components is then created invoking each of those methods and adding the result to the Array private function _Firehose_Array1_c() : Array { var temp : Array = [_Firehose_Button1_i()]; return temp; }
  • 12. Multiple Controls Page 3 of 59 For example, if we had three buttons as peers, the code would like this: <s:Button id="btn1" label="Click Me"/> <s:Button id="btn2" label="Click You"/> <s:Button id="btn3" label="Click It"/> private function _Firehose_Array1_c() : Array { var temp : Array = [_Firehose_Button1_i(), _Firehose_Button2_i(), _Firehose_Button3_i()]; return temp; }
  • 13. Non Skinnable Page 3 of 59 Flex 4 is full of new classes to learn. Let’s start by discussing an old favorite, UIComponent and a new addition Group. UIComponent is still the base class of all components and containers in Flex 4. Group is the base container class. It can hold an unknown number of elements which may be defined in MXML and is akin to a lighter-weight version of Container from the mx component set
  • 14. Skinnable* Page 3 of 59 Two additional new classes in Flex 4 worth noting at this time: SkinnableComponent and SkinnableContainer The SkinnableComponent class is the base class for all components where the view has been separated from component logic through the use of a skin. It is a UIComponent subclass The SkinnableContainer class is a subclass of SkinnableComponent which allows for both a skin and unknown additional elements which may be defined in MXML
  • 15. mxmlContentFactory Page 3 of 59 The goal of all of the work in the generated application code so far has been to set the mxmlContentFactory property of the Firehose class (Application subclass). This property is defined in SkinnableContainer and allows us to specify those unknown MXML children. This property is typed as an IDeferredInstance. this.mxmlContentFactory = new DeferredInstanceFromFunction(_Firehose_Array1_c);
  • 16. IDeferredInstance Page 3 of 59 To be an IDeferredInstance a class must have a single method: public function getInstance():Object { ... return something; } An IDeferredInstance defers the creation of an object until its getInstance() method is called. Each subsequent call returns the originally created instance
  • 17. DeferredInstanceFromFunction Page 3 of 59 Our generated code is simply a function and the mxmlContentFactory expects the IDeferredInstance. The DeferredInstanceFromFunction handles this issue this.mxmlContentFactory = new DeferredInstanceFromFunction(_Firehose_Array1_c); The DeferredInstanceFromFunction class takes a function as its first parameter. When its getInstance() method is called it invokes that method to create the component graph
  • 18. Nested Controls Page 3 of 59 The factory functions generated change a bit when we have nested controls: <s:Button id="btn1" label="Click Me"/> <s:Group> <s:Button id="btn2" label="Click You"/> <s:Button id="btn3" label="Click It"/> </s:Group>
  • 19. Nested Controls Generated Page 3 of 59 private function _Firehose_Array1_c() : Array { var temp : Array = [_Firehose_Button1_i(), _Firehose_Group1_c()]; return temp; } private function _Firehose_Button1_i() : Button { ... } private function _Firehose_Group1_c() : Group { var temp : Group = Group(); temp.mxmlContent = [_Firehose_Button2_i(), _Firehose_Button3_i()]; if (!temp.document) temp.document = this; return temp; }
  • 20. Nested Group Page 3 of 59 In the case of the nested group, you may notice that the mxmlContent property is set, instead of the mxmlContentFactory. var temp : Group = Group(); temp.mxmlContent = [_Firehose_Button2_i(), _Firehose_Button3_i()]; Further, the property is set directly to the Array built by calling these methods. The mxmlContent property is the final home of all children. In this case they are created immediately instead of deferred
  • 21. Application Subclass The next major piece of generated code is the SystemManager subclass. Several important things occur here: The subclass implements IFlexModuleFactory The subclass implements ISWFContext The create() method is overridden The info() method is overridden Page 3 of 59
  • 22. IFlexModuleFactory Page 3 of 59 The newly created SystemManager subclass will implement IFlexModuleFactory and ISWFContext which requires a number of interesting methods. The most interesting ones to us at this moment are: function registerImplementation(interfaceName:String, impl:Object):void; function getImplementation(interfaceName:String):Object; function create(... parameters):Object; function info():Object;
  • 23. registerImplementation() Page 3 of 59 This method allows the Flex framework, and you should you wish, to register Singletons that implement a specific interface. It is sort of a Dependency Injection registration meets singleton and had a baby scenario: public function registerImplementation(interfaceName:String, impl:Object):void; You call this method with an interface you wish to register and an implementing object.
  • 24. getImplementation() Page 3 of 59 This method allows you to getImplementations that were previously registered. So, for example, if you wanted to register a given singleton you could then later retrieve it through the SystemManager public function getImplementation(interfaceName:String):Object
  • 25. create() Page 3 of 59 The create() method is where the magic happens and your app will be instantiated: override public function create(... params):Object { ... varmainClassName:String = params.length == 0?"Firehose“:String(params[0]); varmainClass:Class = Class(getDefinitionByName(mainClassName)); if (!mainClass) return null; varinstance:Object = new mainClass(); if (instance is IFlexModule) (IFlexModule(instance)).moduleFactory = this; return instance; }
  • 26. info() Page 3 of 59 The info() method returns a generic object filled with required and optional properties used to configure the system. Examples of data you may find in the object returned by info(): RSL data, compiled locales, resource bundle names, application domain, main class name, mixins and the correct preloader to use
  • 27. info() Page 3 of 59 In this code snippet from info() you can see where the mixins are specified. This is the way in which Flex applies some of the additional generated code to the system manager. _info = { … mainClassName: "Firehose", mixins: [ "_Firehose_FlexInit", "_Firehose_Styles" ], preloader: mx.preloaders.SparkDownloadProgressBar }
  • 28. Mixin Page 3 of 59 Mixin classes are decorated with the Mixin metadata and have a public static method named init() that takes a IFlexModuleFactory (SystemManager in this case) as an argument. The mixin effectively sets properties and instances on the SystemManager to create the StyleManager, register styles and more
  • 29. Btn Binding Setup Page 3 of 59 Earlier I mentioned that Flex creates a public var for btn on the host component because we have an MXML control named btn. That was true then. However, this is Flex, and in Flex all MXML components are bindable, therefore, that public var actually becomes a getter and setter before we are done
  • 30. Btn Binding Setup Page 3 of 59 [Bindable(event="propertyChange")] public function get btn():spark.components.Button { return this._97884btn; } public function set btn(value:spark.components.Button):void{ varoldValue:Object = this._97884btn; if (oldValue !== value) { this._97884btn = value; if (this.hasEventListener("propertyChange")) this.dispatchEvent( PropertyChangeEvent.createUpdateEvent( this, "btn", oldValue, value)); } }
  • 31. Watcher Setup Page 3 of 59 If you add one Bindable properties to your application. You receive the following additons, which is the code watching for Bindable changes. <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"> <fx:Script> <![CDATA[ [Bindable] public varlblMe:String; ]]> </fx:Script> <s:Button id="btn" label="{lblMe}"/> </s:Application>
  • 32. lblMe Binding Setup Page 3 of 59 private function _Firehose_bindingsSetup():Array { varresult:Array = []; result[0] = new mx.binding.Binding(this, null, null, "btn.label" , "lblMe"); return result; }
  • 33. lblMe Watcher Setup Page 3 of 59 public function setup(target:Object, propertyGetter:Function, staticPropertyGetter:Function, bindings:Array, watchers:Array):void { watchers[0] = new mx.binding.PropertyWatcher("lblMe", {propertyChange: true }, [bindings[0]], propertyGetter ); watchers[0].updateParent(target); } } }
  • 34. Application Constructor Page 3 of 59 if (_watcherSetupUtil == null) { varwatcherSetupUtilClass:Object = getDefinitionByName("_FirehoseWatcherSetupUtil"); watcherSetupUtilClass["init"](null); } _watcherSetupUtil.setup(this, function(propertyName:String):* { return target[propertyName]; }, function(propertyName:String):* { return Firehose[propertyName]; }, bindings, watchers); mx_internal::_bindings = mx_internal::_bindings.concat(bindings); mx_internal::_watchers = mx_internal::_watchers.concat(watchers); for (var i:uint = 0; i < bindings.length; i++) { Binding(bindings[i]).execute(); }
  • 35. GAME TIME Loading and Running 35
  • 36. SWF Load Page 3 of 59 You begin loading your SWF into the browser of your choice. However, you need to remember that SWF is a streaming format, so it arrives a frame at a time. Thanks to your frame metadata, you already told the SWF it should instantiate your SystemManager… so it does.
  • 37. SystemManager Constructor Page 3 of 59 The SystemManager’s constructor is called where it does a few things like figure out if it is the top level or if it has been loaded into another SWF. If it is the top, it sets alignments and scale modes on the stage and then does something extremely important: stop(); We need to wait until we have loaded everything we need before we advance to the next frame and start the application
  • 38. SystemManager Constructor Page 3 of 59 The final line in the SystemManager’s Constructor: if (root && root.loaderInfo) root.loaderInfo.addEventListener(Event.INIT, initHandler); It waits until an INIT event is broadcast from the loaderInfo object. This event is broadcast the moment once everything needed by this first frame is available and the SystemManager’sConnstructor finishes
  • 39. init() Page 3 of 59 One the initHandler() is called, the world gets more interesting. This method does a little cleanup, removes the existing init event listener and some other pieces, however, the two critical things it does for this presentation: Adds another event listener for a method named docFrameListener which is called when the rest of the application is loaded Calls the initialize() method
  • 40. initialize() Page 3 of 59 This method is responsible for creating the PreLoader. The PreLoader itself is a logical class, but it allows us to specify a display class which is displayed to the user to make a better user experience while we load the remainder of the app. This method also starts downloading any RSLs needed for your application… and some it doesn’t need Then we wait until the all of the RSLs are loaded and the remainder of the app is loaded
  • 41. kickOff() Page 3 of 59 When both of these conditions are true (and they can happen in any order) either the preloader or the docFrameHandler catches this fact and ensures kickOff() is called. This method registers a ton of classes as singletons to support everything from fonts to drag and drop. It also instantiates all of those mixins we discussed in the pregame, adding those pieces to the system manager at this time
  • 42. initializeTopLevelWindow() Page 3 of 59 This method does a lot of work to ensure we load correctly and size appropriately, however, the part that interests us most: childManager.initializeTopLevelWindow(w, h); ChildManager is an instance of a class that implements ISystemManagerChildManager, meaning that it has methods to handle the result of adding and removing children as well as the initialize method we call here. In this case, it is an instance of ChildManager
  • 43. ChildManager() Page 3 of 59 Inside of ChildManager, the create() method that was overridden by the compiler is called, effectively creating the instance of your application. A creationComplete event handler is added to the application and the preloader is informed of the application’s existence so that it may leave gracefully when the application is ready Note, the application is created but not yet added to the System Manager… that will happen much later
  • 44. ChildManager() cont Page 3 of 59 Inside of the ChildManager, the addingChild() method is called. This method sets the nestLevel for the new component (nestLevel increase as depth of the component increases) The childAdded() method is called next, which dispatches an ADD event for the child and calls the child’s initialize… And the fun begins
  • 45. PreInitialize Page 3 of 59 The Application initializes several managers and the context menus before beginning the component initialization cycle. This starts by broadcasting FlexEvent.PREINITIALIZE. This is one of the most important events in all of Flex. It means the display object dispatching is initialized, however, it has yet to create any of its visual children. Anything that you want to do which will affect the number or type of children should be done NOW
  • 46. createChildren() Page 3 of 59 Immediately after dispatching the event, the createChildren() method is called. The createChildren() method is responsible for creating all relatively static visual children of a component. In non-skinnable components this method created all visual children directly. In skinnable components, this method invokes validateSkinChange() (which is invoked now and when the skin changes at runtime)
  • 47. validateSkinChange() Page 3 of 59 The validateSkinChange() checks for an existing skin and detaches it if it exists. It then performs the most important operation here, it calls attachSkin() .. if (skin) detachSkin(); attachSkin(); ..
  • 48. attachSkin() Page 3 of 59 The attachSkin() method finds the correct skin for this component, instantiates it, and passes the result to the setSkin() method. In our application, this means creating an instance of the ApplicationSkin. ApplicationSkin is a Skin, which is just a Group and ultimately a UIComponent, so it will have this same life cycle recursively. The setSkin() method sets the _skin property of the class and dispatches a skinChanged event
  • 49. attachSkin() Page 3 of 59 At this point, the owner and hostComponent of the skin are set. The hostComponent of a skin always refers to the object for which it is providing a visual display. Note, not the hostComponent and owner property is set after the class skin instantiated. You cannot access either of these properties during the skin’s construction
  • 50. attachSkin() Page 3 of 59 After the skin is created, the styles of the component are passed to the skin for use. At this point, the skin is added to the component, kicking off its life cycle. The addingChild() method is called, followed by actually adding it via the player APIs. Then the childAdded() method is called. The childAdded method, much like it did for the application, causes the ApplicationSkin’s initialize method to be called
  • 51. Skin PreInitialize Page 3 of 59 The skin now broadcasts its FlexEvent.PREINITIALIZE. It means the skin is initialized, however, it has yet to create any of its visual children. I reiterate, Anything that you want to do which will affect the number or type of children should be done NOW
  • 52. Skin createChildren() Page 3 of 59 Immediately after dispatching the event, the createChildren() method is called. Within the skin, the setMXMLContent method is called. This method takes an array of MXML objects defined in the skin (much like the array you saw in the nested example). All old MXML elements are removed from the skin, and add all of the new elements, using a method named addElement()
  • 53. addElement() Page 3 of 59 Immediately after dispatching the event, the createChildren() method is called. Within the skin, the setMXMLContent method is called. This method takes an array of MXML objects defined in the skin (much like the array you saw in the nested example). All old MXML elements are removed from the skin, and add all of the new elements. We use the word element here as the items we are adding or removing are of type IVisualElement
  • 54. IVisualElement Page 3 of 59 IVisualElement is a new interface to spark which defines the properties that must be present on an object to be correctly sized, positioned and displayed in any type of spark container In spark, controls, containers and even graphic primitives can be IVisualElements. Using this interface is a key component to allowing spark to intermingle these classes
  • 55. elementAdded() cont Page 3 of 59 As the new visual elements are added to the skin, the skin’s elementAdded() method is called. In this method, the elementAdded method of the layout object is also called to inform it of a change, and the invalidateLayering() method is called to inform the skin that the layering of objects may have changed. This invalidation eventually leads to a call to assignDisplayObjects() which reorders the objects
  • 56. elementAdded() Page 3 of 59 In the case where the element is an IGraphicalElement (an interface that descends from IVisualElement to specifically handle the needs of graphics) a special method called addingGraphicalElement() is called and passed the element. IGraphicalElements are not displayObjects on their own like components. They are simply logic and state which draw onto a display object. This means that Flex must identify the correct display object for drawing.
  • 57. elementAdded() Page 3 of 59 In all other cases, the element is assumed to be a displayObject and added to the display list via a method named addObjectToDisplayList() This method ensures the child reaches the display list at the appropriate location Any listeners are notified of the fact that a new element was added and the invalidateDisplayList() and invalidateSize() methods are called to ensure the skin is sized and repositioned
  • 58. More Recursion Page 3 of 59 The addition of each of these elements to the display list causes their initialize() methods to be called. They go through the same process of either instantiating components or instantiating skins, which then instantiate components, which may have skins, with components, with skins….
  • 59. Back Up Page 3 of 59 Starting from the deepest point on the stack of children, each child does the following operations: invalidateProperties() invalidateSize() invalidateDisplayList() sets processedDescriptors = true dispatches its FlexEvent.INITIALIZE event
  • 60. Child Additions Page 3 of 59 Starting from the deepest point on the stack of children, each children performs the following operations: invalidateProperties() invalidateSize() invalidateDisplayList() sets processedDescriptors = true dispatches its FlexEvent.INITIALIZE event
  • 61. FlexEvent.INITIALIZE Page 3 of 59 The initialize event is always broadcast by the inner most child first. It signifies that all of the visual children have been created, however, the children nor the component have been sized or positioned at this time. This is a great place to make visual modifications to children.
  • 62. findSkinParts() Page 3 of 59 After each skin initializes, you return to the attachSkin() method where the skin was first added. We now execute a method named findSkinParts(). This method looks through the SkinParts defined via the [SkinPart] metadata in any SkinnableComponent subclass. If it finds an element with a matching id in the skin, it provided the variable annotated with the [SkinPart] metadata with a reference to that part in the skin
  • 63. partAdded() Page 3 of 59 As each of these parts is identified and the reference provided, the partAdded() method of SkinnableComponent is called and provided both the string name of the skin part and a reference to it: if (this[id] != null && !(this[id] is IFactory)) partAdded(id, this[id]); It is common to override this method in your own components to configure each skin part as it is added. There is a parallel method called partRemoved() which is called with the same arguments if a part is removed.
  • 64. partAdded() Page 3 of 59 The default behavior of the partAdded() method is to dispatch a SkinPartEvent.PART_ADDED event with the partName and instance which can also be used for configuration or other logic
  • 65. SkinStates Page 3 of 59 After all parts are added, the invalidateSkinState() method is called. When you define a SkinnableComponent, you can specify required SkinStates that the skin must fulfill. Meaning it will have those states defined in the skin. [SkinState("up")] [SkinState("over")] --- --- --- --- --- --- <s:states> <s:State name="up" /> <s:State name="over" /> </s:states>
  • 66. SkinStates Page 3 of 59 The invalidateSkinState() method informs the component that the skin needs to know its new visual state As a result of this call, the getCurrentSkinState() method of this component will be called asynchronously. It is expected to return a string that matches one of those valid states It can derive this information in any way it chooses and is not bound to the component state
  • 67. Deferred Page 3 of 59 After all of the skins are attached, the stack returns to the createChildren() method Here it calls a method named createDeferredContentIfNeeded() This method looks for any items specified in the mxmlContentFactory that have not yet been instantiated and creates them now… starting yet another recursive cycle. Note, this is where the Flex compiler assigned our original content
  • 68. Deferred Creation Page 3 of 59 This means initialize is a bit trickier. Skins for a class are created before MXML content, so for instance the ApplicationSkin will be created well before the Button creation begins This is consistent with the use of initialize but, depending on the complexity of the skin may seem strange at first glance
  • 69. Recursion Complete Page 3 of 59 One all of the children are initialized from the inner most to the outer, you will be able to finish the initialize() method of the Application that we started many slides ago. Now we need to worry about invalidation.
  • 70. Invalidation Page 3 of 59 All of this invalidation effectively adds each of these components to a priority queue. This priority queue sorts based on the nestLevel that we mentioned earlier. As these queues are resolved the outer most item toward the deepest have their validateProperties() method called. Then the deepest moving toward the outermost have their validateSize() method called. Finally, from the outer toward deepest, the validateDisplayList() method is called
  • 71. Invalidation Page 3 of 59 After each component has had a chance to complete all necessary validation, it is marked as initialized. Not this is different than the INITIALIZE event Marking a component as Initialized does two important things. it sets the component to visible (if applicable) It dispatches a FlexEvent.CREATION_COMPLETE
  • 72. creationComplete Page 3 of 59 The FlexEvent.CREATION_COMPLETE means that all layout, sizing and positioning is complete and the item can now be visible on the screen. It is just about the worst time to do anything, save for operations that need to know the size and position of a child
  • 73. Application Visible Page 3 of 59 Once all of the children have broadcast their creationComplete event, the time for the application to complete is here The application broadcasts its creationComplete, which is a trigger to System Manager. The System Manager destroys the preloader and adds the Application as a child to the System Manager, making it visible.
  • 74. Application Complete Page 3 of 59 The act of making the application a child of the system manager is among the last acts performed before the System Manager broadcasts a FlexEvent.APPLICATION_COMPLETE from the Application. This signals that the application is ready to be used.
  • 75. Questions Page 3 of 59 ?
  • 76. Page 59 of 59 Me Michael Labriola http://twitter.com/mlabriola