Flex 4 components from the firehose

76
WORLDWARE CONFERENCE Flex 4 Components from the Fire Hose Michael Labriola Senior Consultants Digital Primates twitter.com/mlabriola Page 0 of 59

description

A quick overview of Flex application startup when using spark components

Transcript of Flex 4 components from the firehose

Page 1: Flex 4 components from the firehose

WORLDWARECONFERENCE

Flex 4 Components from the Fire Hose

Michael LabriolaSenior ConsultantsDigital Primates

twitter.com/mlabriola

Page 0 of 59

Page 2: Flex 4 components from the firehose

WORLDWARECONFERENCE

Who am I?

Michael LabriolaSenior ConsultantDigital 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

Page 3: Flex 4 components from the firehose

WORLDWARECONFERENCE

PREGAMEPre-compile, compile and linking time

3

Page 4: Flex 4 components from the firehose

WORLDWARECONFERENCE

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

Page 5: Flex 4 components from the firehose

WORLDWARECONFERENCE

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

Page 6: Flex 4 components from the firehose

WORLDWARECONFERENCE

Generation

This code turns into many generated files. Most important to us are:

1. ActionScript version of your Application subclass2. ActionScript subclass of the system manager3. Getter/Setter generation for mxml properties4. Flex Init Mixin5. Styles, styles and more styles

Page 3 of 59

Page 7: Flex 4 components from the firehose

WORLDWARECONFERENCE

Application Subclass

The first piece of generated code is the Application subclass. When the application is subclassed, several important things occur:

1. Frame metadata is specified2. Properties are created for MXML components in

the document3. Factory functions are created for the MXML

content4. The mxmlContentFactory is set5. Style declaration setup is deferred for a bit

Page 3 of 59

Page 8: Flex 4 components from the firehose

WORLDWARECONFERENCE

Frame metadata

The following metadata is added to the application subclass:

[Frame(extraClass="_Firehose_FlexInit")][Frame(factoryClass="_Firehose_mx_managers_SystemManager")]

1. The first line ensures the inclusion of the Firehose_FlexInit mixin

2. The second line specifies that the Firehose_mx_managers_SystemManager is the bootstrapped root class for your swf

Page 3 of 59

Page 9: Flex 4 components from the firehose

WORLDWARECONFERENCE

MXML Properties

A Bindable public property is created for the MXML instances so that you can refer to these by id in the Application

[Bindable]public var btn : spark.components.Button;

Note this corresponds to the id of the object in the MXML

<s:Button id="btn" label="Click Me"/>

Page 3 of 59

Page 10: Flex 4 components from the firehose

WORLDWARECONFERENCE

Factory Functions

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;

}

Page 3 of 59

Page 11: Flex 4 components from the firehose

WORLDWARECONFERENCE

Factory Functions

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;

}

Page 3 of 59

Page 12: Flex 4 components from the firehose

WORLDWARECONFERENCE

Multiple Controls

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;}

Page 3 of 59

Page 13: Flex 4 components from the firehose

WORLDWARECONFERENCE

Non Skinnable

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

Page 3 of 59

Page 14: Flex 4 components from the firehose

WORLDWARECONFERENCE

Skinnable*

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

Page 3 of 59

Page 15: Flex 4 components from the firehose

WORLDWARECONFERENCE

mxmlContentFactory

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);

Page 3 of 59

Page 16: Flex 4 components from the firehose

WORLDWARECONFERENCE

IDeferredInstance

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

Page 3 of 59

Page 17: Flex 4 components from the firehose

WORLDWARECONFERENCE

DeferredInstanceFromFunction

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

Page 3 of 59

Page 18: Flex 4 components from the firehose

WORLDWARECONFERENCE

Nested Controls

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>

Page 3 of 59

Page 19: Flex 4 components from the firehose

WORLDWARECONFERENCE

Nested Controls Generatedprivate 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;

}

Page 3 of 59

Page 20: Flex 4 components from the firehose

WORLDWARECONFERENCE

Nested Group

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

Page 3 of 59

Page 21: Flex 4 components from the firehose

WORLDWARECONFERENCE

Application Subclass

The next major piece of generated code is the SystemManager subclass. Several important things occur here:

1. The subclass implements IFlexModuleFactory2. The subclass implements ISWFContext3. The create() method is overridden4. The info() method is overridden

Page 3 of 59

Page 22: Flex 4 components from the firehose

WORLDWARECONFERENCE

IFlexModuleFactory

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;

Page 3 of 59

Page 23: Flex 4 components from the firehose

WORLDWARECONFERENCE

registerImplementation()

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.

Page 3 of 59

Page 24: Flex 4 components from the firehose

WORLDWARECONFERENCE

getImplementation()

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

Page 3 of 59

Page 25: Flex 4 components from the firehose

WORLDWARECONFERENCE

create()

The create() method is where the magic happens and your app will be instantiated:

override public function create(... params):Object {...var mainClassName:String =

params.length == 0?"Firehose“:String(params[0]); var mainClass:Class =

Class(getDefinitionByName(mainClassName)); if (!mainClass) return null;

var instance:Object = new mainClass(); if (instance is IFlexModule) (IFlexModule(instance)).moduleFactory = this; return instance;}

Page 3 of 59

Page 26: Flex 4 components from the firehose

WORLDWARECONFERENCE

info()

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

Page 3 of 59

Page 27: Flex 4 components from the firehose

WORLDWARECONFERENCE

info()

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}

Page 3 of 59

Page 28: Flex 4 components from the firehose

WORLDWARECONFERENCE

Mixin

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

Page 3 of 59

Page 29: Flex 4 components from the firehose

WORLDWARECONFERENCE

Btn Binding Setup

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

Page 3 of 59

Page 30: Flex 4 components from the firehose

WORLDWARECONFERENCE

Btn Binding Setup[Bindable(event="propertyChange")]public function get btn():spark.components.Button {

return this._97884btn;}public function set

btn(value:spark.components.Button):void{var oldValue:Object = this._97884btn;if (oldValue !== value) {

this._97884btn = value;if (this.hasEventListener("propertyChange"))

this.dispatchEvent(

PropertyChangeEvent.createUpdateEvent(this, "btn", oldValue, value));

}}

Page 3 of 59

Page 31: Flex 4 components from the firehose

WORLDWARECONFERENCE

Watcher Setup

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 var lblMe:String;

]]></fx:Script><s:Button id="btn" label="{lblMe}"/>

</s:Application>

Page 3 of 59

Page 32: Flex 4 components from the firehose

WORLDWARECONFERENCE

lblMe Binding Setupprivate function _Firehose_bindingsSetup():Array { var result:Array = [];

result[0] = new mx.binding.Binding(this, null, null, "btn.label" , "lblMe");

return result;}

Page 3 of 59

Page 33: Flex 4 components from the firehose

WORLDWARECONFERENCE

lblMe Watcher Setuppublic 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);}

}}

Page 3 of 59

Page 34: Flex 4 components from the firehose

WORLDWARECONFERENCE

Application Constructorif (_watcherSetupUtil == null) { var watcherSetupUtilClass: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();

}

Page 3 of 59

Page 35: Flex 4 components from the firehose

WORLDWARECONFERENCE

GAME TIMELoading and Running

35

Page 36: Flex 4 components from the firehose

WORLDWARECONFERENCE

SWF Load

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.

Page 3 of 59

Page 37: Flex 4 components from the firehose

WORLDWARECONFERENCE

SystemManager Constructor

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

Page 3 of 59

Page 38: Flex 4 components from the firehose

WORLDWARECONFERENCE

SystemManager Constructor

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’s Connstructor finishes

Page 3 of 59

Page 39: Flex 4 components from the firehose

WORLDWARECONFERENCE

init()

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:

1. Adds another event listener for a method named docFrameListener which is called when the rest of the application is loaded

2. Calls the initialize() method

Page 3 of 59

Page 40: Flex 4 components from the firehose

WORLDWARECONFERENCE

initialize()

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

Page 3 of 59

Page 41: Flex 4 components from the firehose

WORLDWARECONFERENCE

kickOff()

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

Page 3 of 59

Page 42: Flex 4 components from the firehose

WORLDWARECONFERENCE

initializeTopLevelWindow()

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

Page 3 of 59

Page 43: Flex 4 components from the firehose

WORLDWARECONFERENCE

ChildManager()

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

Page 3 of 59

Page 44: Flex 4 components from the firehose

WORLDWARECONFERENCE

ChildManager() cont

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

Page 3 of 59

Page 45: Flex 4 components from the firehose

WORLDWARECONFERENCE

PreInitialize

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

Page 3 of 59

Page 46: Flex 4 components from the firehose

WORLDWARECONFERENCE

createChildren()

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)

Page 3 of 59

Page 47: Flex 4 components from the firehose

WORLDWARECONFERENCE

validateSkinChange()

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();

..

Page 3 of 59

Page 48: Flex 4 components from the firehose

WORLDWARECONFERENCE

attachSkin()

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

Page 3 of 59

Page 49: Flex 4 components from the firehose

WORLDWARECONFERENCE

attachSkin()

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

Page 3 of 59

Page 50: Flex 4 components from the firehose

WORLDWARECONFERENCE

attachSkin()

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

Page 3 of 59

Page 51: Flex 4 components from the firehose

WORLDWARECONFERENCE

Skin PreInitialize

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

Page 3 of 59

Page 52: Flex 4 components from the firehose

WORLDWARECONFERENCE

Skin createChildren()

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()

Page 3 of 59

Page 53: Flex 4 components from the firehose

WORLDWARECONFERENCE

addElement()

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

Page 3 of 59

Page 54: Flex 4 components from the firehose

WORLDWARECONFERENCE

IVisualElement

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

Page 3 of 59

Page 55: Flex 4 components from the firehose

WORLDWARECONFERENCE

elementAdded() cont

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

Page 3 of 59

Page 56: Flex 4 components from the firehose

WORLDWARECONFERENCE

elementAdded()

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.

Page 3 of 59

Page 57: Flex 4 components from the firehose

WORLDWARECONFERENCE

elementAdded()

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

Page 3 of 59

Page 58: Flex 4 components from the firehose

WORLDWARECONFERENCE

More Recursion

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….

Page 3 of 59

Page 59: Flex 4 components from the firehose

WORLDWARECONFERENCE

Back Up

Starting from the deepest point on the stack of children, each child does the following operations:

1. invalidateProperties()2. invalidateSize()3. invalidateDisplayList()4. sets processedDescriptors = true5. dispatches its FlexEvent.INITIALIZE event

Page 3 of 59

Page 60: Flex 4 components from the firehose

WORLDWARECONFERENCE

Child Additions

Starting from the deepest point on the stack of children, each children performs the following operations:

1. invalidateProperties()2. invalidateSize()3. invalidateDisplayList()4. sets processedDescriptors = true5. dispatches its FlexEvent.INITIALIZE event

Page 3 of 59

Page 61: Flex 4 components from the firehose

WORLDWARECONFERENCE

FlexEvent.INITIALIZE

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.

Page 3 of 59

Page 62: Flex 4 components from the firehose

WORLDWARECONFERENCE

findSkinParts()

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

Page 3 of 59

Page 63: Flex 4 components from the firehose

WORLDWARECONFERENCE

partAdded()

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.

Page 3 of 59

Page 64: Flex 4 components from the firehose

WORLDWARECONFERENCE

partAdded()

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

Page 3 of 59

Page 65: Flex 4 components from the firehose

WORLDWARECONFERENCE

SkinStates

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>

Page 3 of 59

Page 66: Flex 4 components from the firehose

WORLDWARECONFERENCE

SkinStates

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

Page 3 of 59

Page 67: Flex 4 components from the firehose

WORLDWARECONFERENCE

Deferred

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

Page 3 of 59

Page 68: Flex 4 components from the firehose

WORLDWARECONFERENCE

Deferred Creation

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

Page 3 of 59

Page 69: Flex 4 components from the firehose

WORLDWARECONFERENCE

Recursion Complete

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.

Page 3 of 59

Page 70: Flex 4 components from the firehose

WORLDWARECONFERENCE

Invalidation

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

Page 3 of 59

Page 71: Flex 4 components from the firehose

WORLDWARECONFERENCE

Invalidation

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.

1. it sets the component to visible (if applicable)2. It dispatches a FlexEvent.CREATION_COMPLETE

Page 3 of 59

Page 72: Flex 4 components from the firehose

WORLDWARECONFERENCE

creationComplete

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

Page 3 of 59

Page 73: Flex 4 components from the firehose

WORLDWARECONFERENCE

Application Visible

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.

Page 3 of 59

Page 74: Flex 4 components from the firehose

WORLDWARECONFERENCE

Application Complete

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.

Page 3 of 59

Page 75: Flex 4 components from the firehose

WORLDWARECONFERENCE

Questions

?

Page 3 of 59

Page 76: Flex 4 components from the firehose

WORLDWARECONFERENCE

Me

Michael Labriolahttp://twitter.com/mlabriola

Page 59 of 59