Diving Deep with the Flex Component Life Cycle


Published on

Joshua Jamison of EffectiveUI walks beginner to intermediate level developers through the Flex component life cycle and Flex frame cycle.

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Diving Deep with the Flex Component Life Cycle

  1. 1. Diving Deep with the Flex Component Lifecycle Joshua Jamison EffectiveUI www.effectiveui.com January 30, 2009
  2. 2. Who am I? ‣ Joshua Jamison • Software Architect @ EffectiveUI
  3. 3. 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
  4. 4. What’s this about, anyway? ‣ Flex component lifecycle ‣ Flex frame cycle (“elastic racetrack”)
  5. 5. 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
  6. 6. Elastic Racetrack: introduction image courtesy of Ted Patrick ‣ Flex component lifecycle is built on this frame model ‣ More on this later
  7. 7. A frame in AS3 image courtesy of Sean Christmann
  8. 8. Phases of the Lifecycle ‣ 3 Main Phases: ‣ BIRTH: • construction, con guration, attachment, initialization ‣ LIFE: • invalidation, validation, interaction ‣ DEATH: • detachment, garbage collection
  9. 9. BirthCongratulations: You’re about to have a component.
  10. 10. ConstructionBirth construction con guration attachment initializationLifeDeath
  11. 11. What is a constructor? ‣ A function called to instantiate (create in memory) a new instance of a classBirth construction con guration attachment initializationLifeDeath
  12. 12. How is a constructor invoked? Actionscript: var theLabel : Label = new Label(); MXML: <mx:Label id="theLabel"/>Birth construction con guration attachment initializationLifeDeath
  13. 13. 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 initializationLifeDeath
  14. 14. 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 typeBirth ‣ Must be public construction con guration ‣ Calls super() to invoke superclass constructor; if attachment initialization you don’t, the compiler will!LifeDeath
  15. 15. 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.Birth ‣ Specify “-keep” in the Flex Builder construction con guration compiler arguments and look at the attachment generated code to verify this. initializationLifeDeath
  16. 16. 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.Birth ‣ A good place to add event listeners to the construction con guration object. attachment initializationLifeDeath
  17. 17. 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 necessaryBirth construction con guration attachment initializationLifeDeath
  18. 18. Con gurationBirth construction con guration attachment initializationLifeDeath
  19. 19. 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="value!"/>Birth construction con guration attachment initializationLifeDeath
  20. 20. Hooray: Sample code! <mx:Application ...> ... <local:SampleChild property1="value!"/> </mx:Application> Output: SampleChild constructorBirth SampleChild.property1 setter construction Adding child SampleChild4 con guration attachment initializationLifeDeath
  21. 21. Con guration and Containers ‣ Containers must not expect their children have to be instantiated when properties are set. <mx:Application ...> <local:SampleContainer property1="value!"> <local:SampleChild property1="value!"/> </local:SampleContainer> </mx:Application> SampleContainer constructorBirth construction SampleContainer.property1 setter con guration SampleChild constructor attachment SampleChild.property1 setter initializationLifeDeath
  22. 22. 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 sectionBirth construction con guration attachment initializationLifeDeath
  23. 23. AttachmentBirth construction con guration attachment initializationLifeDeath
  24. 24. 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 initializationLifeDeath
  25. 25. Consider this component: public class A extends UIComponent { public function A() { (It traces all of its methods.) 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(); }
  26. 26. 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.
  27. 27. 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></mx:Application> Output: CONSTRUCTOR CREATECHILDREN COMMITPROPERTIES MEASURE UPDATEDISPLAYLIST ‣ Moral of the story: don’t add components to the stage until you need them.
  28. 28. InitializationBirth construction con guration attachment initializationLifeDeath
  29. 29. Initialization ‣ 2 phases, 3 events: 1. ‘preInitialize’ dispatched Create 2. createChildren(); called 3. ‘initialize’ dispatched Validate 4. rst validation pass occurs 5. ‘creationComplete’ dispatchedBirth construction con guration attachment initializationLifeDeath
  30. 30. 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("textFieldStyleChange", textField_textFieldStyleChangeHandler); ... ... attach } addChild(DisplayObject(textField));
  31. 31. rst validation pass ‣ Invalidation is not part of initialization - only Validation ‣ Validation consists of 3 methods: • commitProperties() • measure() • updateDisplayList() ‣ more on these laterBirth construction con guration attachment initializationLifeDeath
  32. 32. LifeThey grow up so fast.
  33. 33. InvalidationBirthLife invalidation validation interactionDeath
  34. 34. 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()
  35. 35. Invalidation / Validation theory ‣ First, a little theory.
  36. 36. 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
  37. 37. Text-book exampleBad: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 = "";public function set text(value:String):void override protected function{ commitProperties():void{ textSet = true; { _text = value; if(textChanged){ textChanged = true; myLabel.text = _text; textChanged = false; invalidateProperties(); } invalidateSize(); super.commitProperties(); invalidateDisplayList(); }}
  38. 38. The Elastic Racetrack revisited image courtesy of Sean Christmann Invalidation occurs here
  39. 39. Invalidation methods ‣ invalidateProperties() • Any property changes ‣ invalidateSize() • Changes to width or height ‣ invalidateDisplayList() • Changes to child component size or positionBirthLife invalidation validation interactionDeath
  40. 40. 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="Click me!" click="onClick()"/> <test:BadList id="theList" dataProvider="{arr}"/> </mx:VBox></mx:Application>
  41. 41. 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
  42. 42. 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 } this._dataProviderChanged = false; during initialization) } } private function dataProviderChangeHandler( e : Event ) : void { this._dataProviderChanged = true; this.invalidateProperties(); } public function GoodList() {} }
  43. 43. ValidationBirthLife invalidation validation interactionDeath
  44. 44. The Elastic Racetrack revisited Validation occurs here
  45. 45. Validation ‣ Apply the changes deferred during invalidation ‣ Update all visual aspects of the application in preparation for the render phase ‣ 3 methods: • commitProperties() • measure()BirthLife • updateDisplayList() invalidation validation interactionDeath
  46. 46. commitProperties() ‣ Ely says: “Calculate and commit the effects of changes to properties and underlying data.” ‣ Invoked rst - immediately before measurement and layoutBirthLife invalidation validation interactionDeath
  47. 47. 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 screenBirthLife invalidation validation interactionDeath
  48. 48. 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 sizedBirthLife components invalidation validation interactionDeath
  49. 49. 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 forBirth the default values; measuredMinHeightLife invalidation and measuredMinWidth for the minimum. validation interactionDeath
  50. 50. measure() cont. ‣ Not reliable - Framework optimizes away any calls to measure it deems “unecessary”BirthLife invalidation validation interactionDeath
  51. 51. 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-downBirthLife invalidation validation interactionDeath
  52. 52. 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()BirthLife invalidation validation interactionDeath
  53. 53. Elastic Racetrack cont. ‣ User Actions • Dispatch invalidation events • Interact with any non-validation events from this frame (mouse movements, timers, etc.)
  54. 54. Elastic Racetrack Cont. ‣ Invalidate Action • Process all validation calls ‣ Render Action • Do the heavy lifting - actually draw on the screen
  55. 55. The Elastic Racetrack revisited Queued Invalidation Deferred Validation Render!
  56. 56. InteractionBirthLife invalidation validation interactionDeath
  57. 57. 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 eventsBirthLife ‣ Event-based architecture is loosely- invalidation validation coupled interactionDeath
  58. 58. Bene ts of Loosely-Coupled Architectures ‣ Everything becomes more reusable ‣ Components don’t have to know anything about the components in which they’re usedBirthLife invalidation validation interactionDeath
  59. 59. Who can dispatch events? ‣ Subclasses of EventDispatcher • EventDispatcher inherits directly from Object ‣ Simply call dispatchEvent(event) to re off an event when something happensBirthLife invalidation validation interactionDeath
  60. 60. How to tell events apart? ‣ Event class • Different classes allow for customized payloads ‣ “type” eld: a constantBirthLife invalidation validation interactionDeath
  61. 61. Common Events ‣ Event.CHANGE ‣ MouseEvent.CLICK ‣ FlexEvent.CREATION_COMPLETE ‣ Event.RESIZE ‣ MouseEvent.ROLL_OUTBirthLife invalidation validation interactionDeath
  62. 62. Handling Events ‣ <mx:Button id=”theButton” click=”callThisFunction(event)”/> ‣ theButton.addEventListener( MouseEvent .CLICK, callThisFunction )BirthLife invalidation validation interactionDeath
  63. 63. Event Propagation ‣ Three phases: Capturing, Targeting, Bubbling Application Application Capturing Bubbling Phase Phase Target TargetingBirth PhaseLife invalidation validation interactionDeath
  64. 64. Event Propagation ‣ Three phases: Capturing, Targeting, Bubbling <mx:Application initialize="onInitialize()"> <mx:Script> <![CDATA[ public function onInitialize() : void { this.addEventListener( MouseEvent.CLICK, clickHandler, true ); this.addEventListener( MouseEvent.CLICK, clickHandler, false ); outer.addEventListener( MouseEvent.CLICK, clickHandler, true ); outer.addEventListener( MouseEvent.CLICK, clickHandler, false ); inner.addEventListener( MouseEvent.CLICK, clickHandler, true ); inner.addEventListener( MouseEvent.CLICK, clickHandler, false ); button.addEventListener( MouseEvent.CLICK, clickHandler, true ); button.addEventListener( MouseEvent.CLICK, clickHandler, false ); } public function clickHandler( e : Event ) : void { trace("----------------------------------------------------------"); trace("TARGET: " + e.target.id ); trace("CURRENT TARGET: " + e.currentTarget.id ); trace("PHASE: " + ( e.eventPhase == 1 ? "CAPTURE" : ( e.eventPhase == 2 ? "TARGET" : "BUBBLE" ) ) ); } ]]> </mx:Script> <mx:VBox> <mx:Panel id="outer"> <mx:TitleWindow id="inner"> <mx:Button id="button"/> </mx:TitleWindow>Birth </mx:Panel> </mx:VBox>Life </mx:Application> invalidation ‣ validation interactionDeath
  65. 65. 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: eventTestLife PHASE: BUBBLE invalidation validation interactionDeath
  66. 66. 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 owBirthLife invalidation validation interactionDeath
  67. 67. 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)BirthLife invalidation validation interactionDeath
  68. 68. Dispatching events from custom components ‣ MXML: <mx:Metadata> [Event(name="atePizza", type="flash.events.JoshEvent")] </mx:Metadata> ‣ Actionscript: [Event(name="atePizza", type="flash.events.JoshEvent")] public class MyComponent extends UIComponent { ... }BirthLife invalidation validation interactionDeath
  69. 69. DeathAll good things come to an end.
  70. 70. DetachmentBirthLifeDeath detachment garbage collection
  71. 71. 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 moreBirth active references, it *should* be garbage-LifeDeath collected detachment garbage collection
  72. 72. 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 falseBirthLifeDeath detachment garbage collection
  73. 73. Garbage CollectionBirthLifeDeath detachment garbage collection
  74. 74. 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 ‣ Talk to Grant Skinner about forcing GCBirth • http://gskinner.com/blog/archives/2006/08/as3_resource_ma_2.htmlLifeDeath detachment garbage collection
  75. 75. Conclusion ‣ Defer, Defer, DEFER! ‣ Use validation methods correctly ‣ Remember the elastic racetrack
  76. 76. 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