Adobe Flex 3 Component Life CyclePresentation Transcript
Adobe Flex 3 Component
Lifecycle
Presented by RJ Owen
This presentation originally created by
RJ Owen and Brad Umbaugh in 11/08.
Who are we?
‣ RJ Owen
Senior Technical Architect @ EffectiveUI
•
• Adobe Community Expert in Flex
Who are you (hopefully)?
‣ Beginner to intermediate level developers
‣ Anyone who doesn’t currently understand
the lifecycle
‣ Anyone who wants a good review of the
basics
Flex
‣ What is Flex?
A set of components
•
• MXML
• The component lifecycle!
Flex Component Lifecycle
‣ What is it?
The way the framework interacts with
•
every Flex component
• A set of methods the framework calls to
instantiate, control, and destroy
components
• Methods that make the most of the
elastic racetrack
Elastic Racetrack: introduction
image courtesy of Ted Patrick
‣ Flex component lifecycle is built on this
frame model
‣ More on this later
A frame in AS3
image courtesy of Sean Christmann
Phases of the Lifecycle
‣ 3 Main Phases:
‣ BIRTH:
construction, con guration,
•
attachment, initialization
‣ LIFE:
• invalidation, validation, interaction
‣ DEATH:
• detachment, garbage collection
Birth
Congratulations: You’re about to have a component.
Construction
Birth
construction
con guration
attachment
initialization
Life
Death
What is a constructor?
‣ A function called to instantiate (create in
memory) a new instance of a class
Birth
construction
con guration
attachment
initialization
Life
Death
How is a constructor invoked?
Actionscript:
var theLabel : Label = new Label();
MXML:
<mx:Label id=quot;theLabelquot;/>
Birth
construction
con guration
attachment
initialization
Life
Death
What does a constructor have access to?
‣ Properties on the class
‣ Methods on the class
‣ Children have not yet been created!
Birth
construction
con guration
attachment
initialization
Life
Death
What does an ActionScript3
constructor look like?
public function ComponentName()
{
super();
//blah blah blah
}
‣ No required arguments (if it will be used in
MXML); zero, or all optional
‣ Only one per class (no overloading!)
‣ No return type
‣ Must be public
Birth
construction
con guration ‣ Calls super() to invoke superclass constructor; if
attachment
you don’t, the compiler will!
initialization
Life
Death
What does an MXML constructor
look like?
‣ No need to de ne one. In fact, if you try
to put one in an <mx:Script> block, you’ll
get an error.
‣ Why? Remember: MXML = Actionscript. A
constructor is created by the compiler in
the Actionscript generated from the
MXML.
‣ Specify “-keep” in the Flex Builder
Birth
compiler arguments and look at the
construction
con guration
generated code to verify this.
attachment
initialization
Life
Death
What should a constructor do?
‣ Not much.
Since the component’s
children have not yet been created, there’s
not much that can be done.
‣ There are speci c methods (such as
createChildren) that should be used for
most of the things you’d be tempted to
put in a constructor.
‣ A good place to add event listeners to the
Birth
object.
construction
con guration
attachment
initialization
Life
Death
Don’t create or attach children in
the constructor
‣ It’s best to delay the cost of createChildren
calls for added children until it’s necessary
Birth
construction
con guration
attachment
initialization
Life
Death
Con guration
Birth
construction
con guration
attachment
initialization
Life
Death
Con guration
‣ The process of assigning values to
properties on objects
‣ In MXML, properties are assigned in this
phase, before components are attached or
initialized
<local:SampleChild property1=quot;value!quot;/>
Birth
construction
con guration
attachment
initialization
Life
Death
Hooray: Sample code!
<mx:Application ...>
...
<local:SampleChild property1=quot;value!quot;/>
</mx:Application>
Output:
SampleChild constructor
SampleChild.property1 setter
Birth
Adding child SampleChild4
construction
con guration
attachment
initialization
Life
Death
Con guration and Containers
‣ Containers must not expect their children
have to be instantiated when properties
are set.
<mx:Application ...>
<local:SampleContainer property1=quot;value!quot;>
<local:SampleChild property1=quot;value!quot;/>
</local:SampleContainer>
</mx:Application>
SampleContainer constructor
Birth
SampleContainer.property1 setter
construction
SampleChild constructor
con guration
attachment SampleChild.property1 setter
initialization
Life
Death
Con guration Optimization
‣ To avoid performance bottlenecks, make
your setters fast and defer any real work
until validation
‣ We’ll talk more about deferment in the
validation / invalidation section
Birth
construction
con guration
attachment
initialization
Life
Death
Attachment
Birth
construction
con guration
attachment
initialization
Life
Death
What is attachment?
‣ Adding a component to the display list
(addChild, addChildAt, MXML declaration)
‣ The component lifecycle is stalled after
con guration until attachment occurs.
Birth
construction
con guration
attachment
initialization
Life
Death
Consider this component:
public class A extends UIComponent
(It traces all of its methods.)
{
public function A() {
trace( quot;CONSTRUCTORquot; );
super();
}
override protected function createChildren() : void {
trace( quot;CREATECHILDRENquot; );
super.createChildren();
}
override protected function measure() : void {
trace( quot;MEASUREquot; );
super.measure();
}
override protected function updateDisplayList(width:Number, height:Number) : void {
trace( quot;UPDATEDISPLAYLISTquot; );
super.updateDisplayList(width,height);
}
override protected function commitProperties():void {
trace( quot;COMMITPROPERTIESquot; );
super.commitProperties();
}
And this application:
<mx:Application ...>
<mx:Script>
<![CDATA[
override protected function createChildren() : void {
super.createChildren();
var a : A = new A();
}
]]>
</mx:Script>
</mx:Application>
Output: CONSTRUCTOR
‣ Without attachment, the rest of the lifecycle
doesn’t happen.
But what about this application?
<mx:Application ...>
<mx:Script>
<![CDATA[
override protected function createChildren() : void {
super.createChildren();
var a : A = new A();
this.addChild( a );
}
]]>
</mx:Script>
Output: CONSTRUCTOR
</mx:Application>
CREATECHILDREN
COMMITPROPERTIES
MEASURE
UPDATEDISPLAYLIST
‣ Moral of the story: don’t add components to the
stage until you need them.
Initialization
Birth
construction
con guration
attachment
initialization
Life
Death
Initialization
‣ 2 phases, 3 events:
1. ‘preInitialize’ dispatched
Create 2. createChildren(); called
3. ‘initialize’ dispatched
Validate 4. rst validation pass occurs
5. ‘creationComplete’ dispatched
Birth
construction
con guration
attachment
initialization
Life
Death
createChildren()
‣ MXML uses the createChildren() method to add
children to containers
‣ Override this method to add children using AS
Follow MXML’s creation strategy: create,
•
con gure, attach
override protected function createChildren():void
{
...
create textField = new UITextField();
textField.enabled = enabled;
con gure textField.ignorePadding = true;
textField.addEventListener(quot;textFieldStyleChangequot;,
textField_textFieldStyleChangeHandler);
...
...
attach addChild(DisplayObject(textField));
}
createChildren() cont.
‣ Defer creating dynamic and data-driven
components until commitProperties()
‣ UIComponent.createChildren() is empty,
but it’s good practice to always call
super.createChildren() anyway
Birth
construction
con guration
attachment
initialization
Life
Death
rst validation pass
‣ Invalidation is not part of initialization -
only Validation
‣ Validation consists of 3 methods:
• commitProperties()
• measure()
• updateDisplayList()
‣ more on these later
Birth
construction
con guration
attachment
initialization
Life
Death
Life
They grow up so fast.
Invalidation
Birth
Life
invalidation
validation
interaction
Death
Invalidation / Validation cycle
‣ Flex imposes deferred validation on the
Flash API
• goal: defer screen updates until all
properties have been set
‣ 3 main method pairs to be aware of:
• invalidateProperties() ->
commitProperties()
• invalidateSize() -> measure()
• invalidateDisplayList() ->
updateDisplayList()
Invalidation / Validation theory
‣ First, a little theory.
Deferment
‣ Deferment is the central concept to
understand in the component Life-cycle
‣ Use private variables and boolean ags to
defer setting any render-related
properties until the proper validation
method
Text-book example
Bad:
public function set text(value:String):void
{
myLabel.text = value;
// Possible Error! during first config phase,
// myLabel might not exist!
}
Good:
private var _text:String = quot;quot;;
override protected function
public function set text(value:String):void
{ commitProperties():void{
{
textSet = true;
_text = value; if(textChanged){
myLabel.text = _text;
textChanged = true;
textChanged = false;
}
invalidateProperties();
invalidateSize(); super.commitProperties();
}
invalidateDisplayList();
}
The Elastic Racetrack revisited
image courtesy of Sean Christmann
Invalidation occurs here
Invalidation methods
‣ invalidateProperties()
Any property changes
•
‣ invalidateSize()
• Changes to width or height
‣ invalidateDisplayList()
• Changes to child component size or
position
Birth
Life
invalidation
validation
interaction
Death
Invalidation example 1
<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 );
}
}
]]>
</mx:Script>
<mx:VBox>
<mx:Button label=quot;Click me!quot; click=quot;onClick()quot;/>
<test:BadList id=quot;theListquot; dataProvider=quot;{arr}quot;/>
</mx:VBox>
</mx:Application>
Invalidation example 2
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 );
}
}
public function BadList() {}
}
Result: dataProviderChangeHandler called 20 times
Invalidation example 3
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 );
this._dataProviderChanged = true;
this.invalidateProperties();
}
override protected function commitProperties():void {
super.commitProperties();
if( this._dataProviderChanged ) {
this.removeAllChildren();
for each( var n : Number in this._dataProvider ) {
var l : Label = new Label();
l.text = n.toString(); Result: commitProperties
this.addChild( l );
called only twice (once
}
during initialization)
this._dataProviderChanged = false;
}
}
private function dataProviderChangeHandler( e : Event ) : void {
this._dataProviderChanged = true;
this.invalidateProperties();
}
public function GoodList() {}
}
Validation
Birth
Life
invalidation
validation
interaction
Death
The Elastic Racetrack revisited
Validation occurs here
Validation
‣ Apply the changes deferred during
invalidation
‣ Update all visual aspects of the
application in preparation for the render
phase
‣ 3 methods:
• commitProperties()
• measure()
Birth
• updateDisplayList()
Life
invalidation
validation
interaction
Death
commitProperties()
‣ Ely says: “Calculate and commit the effects
of changes to properties and underlying
data.”
‣ Invoked rst - immediately before
measurement and layout
Birth
Life
invalidation
validation
interaction
Death
commitProperties() cont.
‣ ALL changes based on property and data
events go here
‣ Even creating and destroying children, so
long as they’re based on changes to
properties or underlying data
‣ Example: any list based component with
empty renderers on the screen
Birth
Life
invalidation
validation
interaction
Death
measure()
‣ Component calculates its preferred
(“default”) and minimum proportions
based on content, layout rules,
constraints.
‣ Measure is called bottom up - lowest
children rst
‣ Caused by “invalidateSize()”
‣ NEVER called for explicitly sized
Birth
components
Life
invalidation
validation
interaction
Death
overriding measure()
‣ Used for dynamic layout containers (VBox,
etc.)
‣ Use getExplicitOrMeasuredWidth() (or
height) to get child proportions
‣ ALWAYS called during initialization
‣ Call super.measure() rst!
‣ Set measuredHeight, measuredWidth for
the default values; measuredMinHeight
Birth
and measuredMinWidth for the minimum.
Life
invalidation
validation
interaction
Death
measure() cont.
‣ Not reliable - Framework optimizes away
any calls to measure it deems
“unecessary”
‣ Ely says: “Start by explicitly sizing your
component and implement this later.”
Birth
Life
invalidation
validation
interaction
Death
updateDisplayList()
‣ All drawing and layout code goes here,
making this the core method for all
container objects
‣ Caused by invalidateDisplayList();
‣ Concerned with repositioning and
resizing children
‣ updateDisplayList() is called top-down
Birth
Life
invalidation
validation
interaction
Death
Overriding updateDisplayList()
‣ Usually call super.updateDisplayList() rst
• super() is optional - don’t call it if you’re
overriding everything it does
‣ Size and lay out children using move(x,y)
and setActualSize(w,h) if possible
• I never have good luck with
setActualSize()
Birth
Life
invalidation
validation
interaction
Death
Elastic Racetrack cont.
‣ User Actions
Dispatch invalidation events
•
• Interact with any non-validation events
from this frame (mouse movements,
timers, etc.)
Elastic Racetrack Cont.
‣ Invalidate Action
Process all validation calls
•
‣ Render Action
• Do the heavy lifting - actually draw on
the screen
The Elastic Racetrack revisited
Queued Invalidation
Deferred Validation
Render!
Interaction
Birth
Life
invalidation
validation
interaction
Death
How do objects know when
something happens?
‣ Events: objects passed around when
anything interesting goes on (clicks,
moves, changes, timers...)
‣ If something happens to a component, it
“ res” or “dispatches” the event
‣ If another component wants to know
when something happens, it “listens” for
events
Birth
‣ Event-based architecture is loosely-
Life
invalidation
coupled
validation
interaction
Death
Bene ts of Loosely-Coupled
Architectures
‣ Everything becomes more reusable
‣ Components don’t have to know anything
about the components in which they’re
used
Birth
Life
invalidation
validation
interaction
Death
Who can dispatch events?
‣ Subclasses of EventDispatcher
EventDispatcher inherits directly from
•
Object
‣ Simply call dispatchEvent(event) to re off
an event when something happens
Birth
Life
invalidation
validation
interaction
Death
How to tell events apart?
‣ Event class
Different classes allow for customized
•
payloads
‣ “type” eld: a constant
Birth
Life
invalidation
validation
interaction
Death
Common Events
‣ Event.CHANGE
‣ MouseEvent.CLICK
‣ FlexEvent.CREATION_COMPLETE
‣ Event.RESIZE
‣ MouseEvent.ROLL_OUT
Birth
Life
invalidation
validation
interaction
Death
Handling Events
‣ <mx:Button id=”theButton”
click=”callThisFunction(event)”/>
‣ theButton.addEventListener( MouseEvent
.CLICK, callThisFunction )
Birth
Life
invalidation
validation
interaction
Death
Event Propagation
‣ Three phases: Capturing, Targeting, Bubbling
Application Application
Capturing Bubbling
Phase Phase
Target
Targeting
Phase
Birth
Life
invalidation
validation
interaction
Death
Event Propagation
----------------------------------------------------------
TARGET: button
CURRENT TARGET: eventTest
PHASE: CAPTURE
----------------------------------------------------------
TARGET: button
CURRENT TARGET: outer
PHASE: CAPTURE
----------------------------------------------------------
TARGET: button
CURRENT TARGET: inner
PHASE: CAPTURE
----------------------------------------------------------
TARGET: button
CURRENT TARGET: button
PHASE: TARGET
----------------------------------------------------------
TARGET: button
CURRENT TARGET: inner
PHASE: BUBBLE
----------------------------------------------------------
TARGET: button
CURRENT TARGET: outer
PHASE: BUBBLE
----------------------------------------------------------
Birth TARGET: button
CURRENT TARGET: eventTest
Life
PHASE: BUBBLE
invalidation
validation
interaction
Death
Stopping events from propagating
‣ stopPropagation() : Prevents processing
of any event listeners in nodes
subsequent to the current node in the
event ow
‣ stopImmediatePropagation() : Prevents
processing of any event listeners in the
current node and any subsequent nodes
in the event ow
Birth
Life
invalidation
validation
interaction
Death
target vs. currentTarget
‣ target: the object that dispatched the
event (doesn’t change)
‣ currentTarget: the object who is currently
being checked for speci c event listeners
(changes)
Birth
Life
invalidation
validation
interaction
Death
Dispatching events from custom
components
‣ MXML:
<mx:Metadata>
[Event(name=quot;atePizzaquot;, type=quot;flash.events.BradEventquot;)]
</mx:Metadata>
‣ Actionscript:
[Event(name=quot;atePizzaquot;, type=quot;flash.events.BradEventquot;)]
public class MyComponent extends UIComponent
{
...
}
Birth
Life
invalidation
validation
interaction
Death
gutterShark: event manager
‣ guttershark is Aaron Smith’s “Actionscript
3 Productivity Library”
‣ Contains a lot of stuff commonly needed
when developing Flash web sites
‣ Includes an EventManager that’s helpful
Birth
Life
invalidation
validation
interaction
Death
gutterShark: event manager
<mx:Application
initialize=quot;onInitialize()quot;>
<mx:Script>
<![CDATA[
import net.guttershark.events.EventManager;
private var em : EventManager;
public function onInitialize( e : Event = null ) : void {
em = EventManager.gi();
em.handleEvents(theButton,this,quot;onButtonquot;);
}
public function onButtonClick() : void {
theLabel.text = quot;CLICKquot;;
}
public function onButtonMouseOver() : void {
theLabel.text = quot;MOUSE OVERquot;;
}
public function onButtonMouseOut() : void {
theLabel.text = quot;MOUSE OUTquot;;
}
]]>
Birth </mx:Script>
<mx:VBox>
Life
<mx:Button id=quot;theButtonquot; label=quot;Click Me!quot;/>
invalidation <mx:Label id=quot;theLabelquot;/>
</mx:VBox>
validation
</mx:Application>
interaction
Death
gutterShark: event manager
‣ Supports many different types of events
and the addition of more
‣ Easy integration with Google Analytics,
Atlas, Webtrends
‣ http://www.guttershark.net
Birth
Life
invalidation
validation
interaction
Death
Death
All good things come to an end.
Detachment
Birth
Life
Death
detachment
garbage
collection
Detachment
‣ “Detachment” refers to the process of
removing a child from the display list
‣ These children can be re-parented
(brought back to life) or abandoned to die
‣ Abandoned components don’t get
validation calls and aren’t drawn
‣ If an abandoned component has no more
active references, it *should* be garbage-
Birth
collected
Life
Death
detachment
garbage
collection
Detachment cont.
‣ Re-parenting isn’t cheap, but it’s cheaper
than re-creating the same component
twice
‣ Children do not need to be removed from
their parent before being re-parented, but
always should be
‣ Consider hiding rather than removing
• set visible and includeInLayout to false
Birth
Life
Death
detachment
garbage
collection
Garbage Collection
Birth
Life
Death
detachment
garbage
collection
Garbage Collection
‣ The process by which memory is returned
to the system
‣ Only objects with no remaining references
to them will be gc’d
• Set references to detached children to
“null” to mark them for GC
‣ Consider using weak references on event
listeners
‣ Talk to Grant Skinner about forcing GC
Birth
Life
http://gskinner.com/blog/archives/2006/08/as3_resource_ma_2.html
•
Death
detachment
garbage
collection
Conclusion
‣ Defer, Defer, DEFER!
‣ Use validation methods correctly
‣ Remember the elastic racetrack
‣ Always look on the bright side of
detachment.
References
‣ Ely Green eld: “Building a Flex Component”
• http://www.on ex.org/ACDS/
BuildingAFlexComponent.pdf
‣ Cha c Kazoun, Joey Lott: “Programming Flex 2” by
O’Reilly
• http://oreilly.com/catalog/9780596526894/
‣ Colin Moock: “Essential Actionscript 3.0” by O’Reilly
• http://oreilly.com/catalog/9780596526948/
index.html
1–1 of 1 previous next