Copyright 2009 Tikal Knowledge, Ltd. | 1 | Creating Custom Creating Custom Components in Flex 3 Components in Flex 3
Dec 19, 2014
Copyright 2009 Tikal Knowledge, Ltd. | 1 |
Creating Custom Components Creating Custom Components in Flex 3in Flex 3
Copyright 2009 Tikal Knowledge, Ltd. | 2 |
Vocab Lesson Vocab Lesson
Flex Component Lifecycle» A mechanism the framework uses to create, manage and destroy
components» A mechanism that makes the most of the player rendering model.
Halo: Component architecture used in Flex 3 and earlier versions.
Copyright 2009 Tikal Knowledge, Ltd. | 3 |
Halo Component Architecture Patterns Halo Component Architecture Patterns
Defining Patterns in Halo» Invalidation/Validation Model
• Methodology to aggregate changes and defer work until an optimal later time
» Event Driven Interaction Model • Inform the component if something is about to or has
already occurred » Composition
• Parameterization of a component’s appearance or content.
• Most often occurs through factories and item renderers.
Copyright 2009 Tikal Knowledge, Ltd. | 4 |
Invalidation / Validation theoryInvalidation / Validation theory
Flash player Rendering model
Copyright 2009 Tikal Knowledge, Ltd. | 5 |
Flash player framesFlash player frames
The Flash Player runs through each frame of a timeline one by one at a speed determined by the frame rate (fps)
Each frame consists of executing ActionScript code and rendering
FP5 allow executing actionscript when a particular events occur
EnterFrame is fired when a frame begins
Frame rate is configurable (compiled with the swf) but is limited by browser/Os
Copyright 2009 Tikal Knowledge, Ltd. | 6 |
Flash player framesFlash player frames
On one hand : Flex application consists on 2 frames
On the other hand : enterFrame event is continuously fired
? Question ?
Copyright 2009 Tikal Knowledge, Ltd. | 7 |
Flash player framesFlash player frames
! Answer !
Copyright 2009 Tikal Knowledge, Ltd. | 8 |
The Elastic Racetrack The Elastic Racetrack
Flex component lifecycle is built atop this frame model
Invalidation/Validation takes advantage of the elastic racetrack to get work done in an efficient manner.
Images courtesy of Sean Christmann
Traditional Flash Player Elastic Racetrack
Copyright 2009 Tikal Knowledge, Ltd. | 9 |
The Elastic Racetrack The Elastic Racetrack
Images courtesy of Sean Christmann
User Actions• Interact with any non- validation events from this frame (mouse movements,timers, ENTER_FRAMEs etc.)• Dispatch invalidation events(invalidateProperties etc.)
Invalidate Action• Process all validation calls(CommitProperties)
Render Action• Do the heavy lifting - actually draw on the screen
Event.updateAfterEvent -> Stage.Invalidate->Render event->Validation methods
Copyright 2009 Tikal Knowledge, Ltd. | 10 |
Deferred Validation ModelDeferred Validation Model
Waiting for update request
Waiting for update request
Update Requested
Update Requested
InvalidationInvalidation
ValidationValidation
Validation occurs right before Rendering
Invalidation
Validation
Copyright 2009 Tikal Knowledge, Ltd. | 11 |
Halo Component Lifecycle – Broken Down Halo Component Lifecycle – Broken Down
3 Phase Lifecycle1. Initialization (Birth)
• Construction• Configuration• Attachment• Initialization
2. Updating (Life)• Component responds to changes by using the
Invalidation/Validation Model - Interaction -> invalidation - > validation
3. Destruction (Death)• Out of sight, out of mind • Detachment • Garbage collection
Copyright 2009 Tikal Knowledge, Ltd. | 12 |
Consider this component:Consider this component:
public class A extends UIComponent
{
public function A() {
trace( "CONSTRUCTOR" );
super();
}
override protected function createChildren() : void {
trace( "CREATECHILDREN" );
super.createChildren();
}
override protected function measure() : void {
trace( "MEASURE" );
super.measure();
}
override protected function updateDisplayList(width:Number, height:Number) : void {
trace( "UPDATEDISPLAYLIST" );
super.updateDisplayList(width,height);
}
override protected function commitProperties():void {
trace( "COMMITPROPERTIES" );
super.commitProperties();
}
Copyright 2009 Tikal Knowledge, Ltd. | 13 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
Construction: Component begins its lifecycle » Component is instantiated (create in memory),
through the new operator in ActionScript or in MXML» No required arguments (if it will be used in MXML);
zero, or all optional » Calls super() to invoke superclass constructor; if you
don’t, the compiler will!» Constructor can add event listeners, hard code
initialization properties of super classes» Have access to class properties and methods» Children have not yet been created!» Minimal work should occur here (not JIT’ed).» Don’t create or attach children in the constructor
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 14 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
Configuration: Component properties are set internally to be processed later» In MXML, properties are assigned in this
phase, before children are attached or initialized.
Sample.mxml wants to expose a text property to update the label
<mx:Canvas>
<mx:Label id="myLabel"/>
</mx:Canvas>
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
<mx:Application ...>...
<local:Sample text="value!"/></mx:Application>
Output:Sample constructorSample.text setterAdding Sample to display list (which creates myLabel)
Copyright 2009 Tikal Knowledge, Ltd. | 15 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
» Properties must expect that children haven’t been created yet.Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Bad:public function set text(value:String):void}
myLabel.text = value;// Possible Error! during first config phase,// myLabel might not exist!
{
Copyright 2009 Tikal Knowledge, Ltd. | 16 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
» In ActionScript, properties might be assigned in this phase, before children are attached or initialized
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
//Developer might code this: var comp: SampleChild = new SampleChild(); addChild(comp); comp.property1 = value1; //off the hook
//Or this: var comp: SampleChild = new SampleChild(); comp.property1 = value1; //throw exception addChild(comp);
Exception in case the property try to
access a child
Copyright 2009 Tikal Knowledge, Ltd. | 17 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
» To avoid performance bottlenecks, make your setters fast and defer any real work until validation using invalidatin/validation
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Good :private var _text:String = "";private var textChanged:boolean = false;public function set text(value:String):void}
_text = value; //storetextChanged = true; //markinvalidateProperties(); //invalidateinvalidateSize();invalidateDisplayList();
}override protected function commitProperties():void{
super.commitProperties();if(textChanged){ myLabel.text = text; textChanged = false;} //don’t forget to unmark !!!
{}
Copyright 2009 Tikal Knowledge, Ltd. | 18 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
Attachment: Addition to the display list
Component is added to the display list through addChild, addChildAt, MXML declaration.
Without attachment, component lifecycle will stall.
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)<mx:Application ...>
<mx:Script><![CDATA[override protected function createChildren() : void {
super.createChildren();var a : A = new A(); Output: CONSTRUCTORthis.addChild( a ); CREATECHILDREN
} ]]></mx:Script>
</mx:Application>
COMMITPROPERTIESMEASUREUPDATEDISPLAYLISTCREATIONCOMPLETE
Moral of the story: don’t add components to the stage until you need them.
Copyright 2009 Tikal Knowledge, Ltd. | 19 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
Initialization main steps ( not all of them ! full list)
1.preinitialize event is dispatched2.createChildren() is called3.Calling invalidation methods4.initialize event is dispatched 5.First full validation pass occurs6.creationComplete event is dispatched
Full invalidation/validation cycle is invoked (we will come back to this)
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Create
Validate
Copyright 2009 Tikal Knowledge, Ltd. | 20 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
createChildren() - The attachment workhorse » Ideal place for adding children that are required
throughout the lifetime of the component » Dynamic or data-driven children which should be added
in commitProperties() » Check to make sure the children have not been
instantiated already» Follow the same pattern Flex uses: construct, configure,
attach. if (!stopButton)
}
stopButton = new Button();
stopButton.label = "stop";
stopButton.addEventListener(MouseEvent.CLICK,stopBtnClickHandler);
controlBar.addChild(stopButton);
{
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Construct
Configure
Attach
Copyright 2009 Tikal Knowledge, Ltd. | 21 |
Lifecycle Phase 1: Initialization Lifecycle Phase 1: Initialization
First full invalidation/validation pass occurs here» Invalidation is captured by 3 methods:
• invalidateProperties()• invalidateSize()• invalidateDisplayList()
» Validation is captured by 3 methods:• commitProperties()• measure()• updateDisplayList()
Phase 1 Done!
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 22 |
Phase 2: UpdatingPhase 2: Updating
Our component has been created!
It’s a living, breathing entity, and now it needs to know how to update.
Updates occur» When a user interacts with a component» When methods or properties are invoked/set
A component should use Flex’s Invalidation/Validation Model to respond to changes.
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 23 |
Deferred Validation Model: An Optimization Deferred Validation Model: An Optimization
Invalidation/validation model is split into 3 phases:
Update component properties
Update sizing & measurement information
Update drawing and positioning
invalidateProperties()
invalidateSize()
invalidateDisplayList()
commitProperties()
measure()
updateDisplayList()
Copyright 2009 Tikal Knowledge, Ltd. | 24 |
commitProperties()commitProperties()
Property management phase of validation» Purpose: Commit values typically set
using a property setter» Invoked by the framework before
measurement and layout. » There is a definite pattern that should be
followed in order to avoid extra work. • Dirty flags and storage variables
» This is the place to add/remove children not required through the life of the entire component (as opposed to createChildren())
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 25 |
Invalidation/Validation exampleInvalidation/Validation example
The idea : bind a list of labels to an array. The list will add a label to the display list for each item in the array.
<mx:Application>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var arr : ArrayCollection = new ArrayCollection();
public function onClick() : void
{
var c : int = 0;
while( c++ < 20 )
{
arr.addItem( c ); //add 20 items to the array collection
}
}
]]>
</mx:Script>
<mx:VBox>
<mx:Button label="Click me!" click="onClick()"/>
<test:BadList id="theList" dataProvider="{arr}"/> //the list creates a label for each entity in the array
</mx:VBox>
</mx:Application>
Copyright 2009 Tikal Knowledge, Ltd. | 26 |
Invalidation/Validation Bad implementation Invalidation/Validation Bad implementation public class BadList extends VBox
}
private var _dataProvider : ArrayCollection;
public function set dataProvider( arr : ArrayCollection ) : void
{
this._dataProvider = arr;
arr.addEventListener( CollectionEvent.COLLECTION_CHANGE, dataProviderChangeHandler );
}
private function dataProviderChangeHandler( e : Event ) : void
{
this.removeAllChildren();
for each( var n : Number in this._dataProvider )
{
var l : Label = new Label();
l.text = n.toString();
this.addChild( l );
}
}
} Result: dataProviderChangeHandler called 20 times
Copyright 2009 Tikal Knowledge, Ltd. | 27 |
Invalidation/Validation Good implementation Invalidation/Validation Good implementation public class GoodList extends VBox
}
private var _dataProvider : ArrayCollection;
private var _dataProviderChanged : Boolean = false;
public function set dataProvider( arr : ArrayCollection ) : void {
This.dataProvider = arr;
arr.addEventListener( CollectionEvent.COLLECTION_CHANGE, dataProviderChangeHandler );
dataProviderChanged = true;
invalidateProperties();
}
override protected function commitProperties():void {
super.commitProperties();
if( dataProviderChanged ) {
removeAllChildren();
for each( var n : Number in this._dataProvider ) {
var l : Label = new Label();
l.text = n.toString();
addChild( l ); }
this._dataProviderChanged = false;
}
}
private function dataProviderChangeHandler( e : Event ) : void {
dataProviderChanged = true;
invalidateProperties();
} Result: commitProperties called only twice (once during initialization)
Copyright 2009 Tikal Knowledge, Ltd. | 28 |
measure()measure()
Sizing phase of validation Purpose: Component can calculate its
‘natural’/preferred/default size based on content and layout rules.
Implicitly invoked when component children change size. (Don’t call measure() on your children).
Measurement occurs from the bottom up. <mx:Application>
<mx:HBox> <mx:Button /></mx:HBox>
</mx:Application>
Don’t count on it: Framework optimizes away unnecessary calls to measure().
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 29 |
Overriding measure()Overriding measure()
Used for dynamic layout containers (Vbox etc.)
Use getExplicitOrMeasuredWidth() for children which are UiComponents
Use width for non UiComponents
ALWAYS called during initialization
Call super.measure() first!
Set measuredHeight, measuredWidth for
the default values; measuredMinHeight
and measuredMinWidth for the minimum.
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
To get up and running fast, explicitly size your
component.
Copyright 2009 Tikal Knowledge, Ltd. | 30 |
measure() examplemeasure() example
override protected function measure( ):void
}
super.measure( );
measuredHeight = measuredMinHeight = currentIcon.height;
measuredWidth = measuredMinWidth = currentIcon.width + displayNameLabel.getExplicitOrMeasuredWidth( );
{
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 31 |
updateDisplayList()updateDisplayList()
Layout and Drawing Phase of Invalidation Purpose: Lay out component contents and perform any
drawing
Layout and positioning occurs from the top down, given:
<mx:Application><mx:HBox> <mx:Button /></mx:HBox>
</mx:Application>
super() is optional - don’t call it if you’re overriding everything it does
Size and lay out children
If the child is a UIComponent, size it with setActualSize() and position it with move()
» If the child is not a UIComponent, set the x, y, width and height properties.
Good place to use Flash Player Drawing API
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 32 |
updateDisplayList() exampleupdateDisplayList() example
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth,unscaledHeight);
displayNameLabel.move(currentIcon.x + currentIcon.width,0);
displayNameLabel.setActualSize(unscaledWidth-currentIcon.width, unscaledHeight);
{
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 33 |
Phase 3: Destruction Phase 3: Destruction
Destroying the component » Detachment: Remove the component from the
display list» Components do not get validated or drawn
when off the display list » Once off the display list:
• You can re-parent the component, and it will be brought back to life.
• Re-parenting is cheaper then re-instantiating a component
» Garbage Collection• No active references can be tough• Common culprits include event listeners,
dictionaries and timers.
Construction
Configuration
Attachment
Initialization
Invalidation
Validation
Detachment
Garbage Collection
Initialization
(Born)
Updating(Life)
Destruction
(Death)
Copyright 2009 Tikal Knowledge, Ltd. | 34 |
In Conclusion…In Conclusion…
» Flash Player Elastic Racetrack: Learn it, love it, live it.
» Invalidation: All the cool kids are doing it.
» The best component lifecycle reference is right in front of you: Read Framework Code.
Resources
» Elastic Racetrack» Updated Elastic Racetrack» Building custom components (ppt, source, video)» Diving deep with Flex component lifecycle