Share 'Introduction' on Delicious Share 'Introduction' on Facebook Share 'Introduction' on Google Bookmarks Share 'Introduction' on Twitter

  1. What is a life cycle framework?
    1. Example code: Life cycle and non life cycle component
  2. What is a component life cycle?
    1. Creation
    2. Initialization
    3. Drawing and Layouting
    4. Update
    5. Disposal
  3. Life cycle framework features
    1. Organizing component code
    2. Method invocation order
    3. Deferred rendering
    4. Managing nested components
  4. Leave a Comment

Introduction

This document will introduce you to the meanings of the LifeCycle framework of AS3Commons UI. After reading this document you are familiar with the terms life cycle and invalidation. You will find LifeCycle a great piece of software that helps you to create your own user interface components. You will already know the basics of LifeCycle and are ready to step deeper into the LifeCycle documentation.

What is a life cycle framework?

When you create a component you always will encounter life cycle related questions. If you are an advanced developer, you perhaps have already some answers or you even use a framework that provides a life cycle for you.

  • Where to put the code to draw the component’s visuals?
  • Where to put the code to update my component?
  • How to update the component efficiently?
  • Where to put the code to set up or remove event listeners?
  • Where to put the code to create sub components?
  • How to update sub components?
  • How to manage dependencies between components?

A life cycle framework deals with all of those questions. It helps you to minimise the effort to sort the different responsibilties and functionalities of your component to the right places. Instead of writing a component entirely from the scratch, you let the life cycle framework call appropriate methods on your component and follow the conventions what to do in those methods. This is the inversion of control principle (IoC on Wikipedia). Inversion of control (IoC) is a way to generalize complex logical dependencies into reusable software solutions. The control flow is managed by the framework (called the IoC container) and not in the client’s code. While the term IoC framework mostly refers to an application framework such as Robotlegs or PureMVC, a life cycle framework targets just user interface components and is an important part of each component framework such as Flex.

Example code: Life cycle and non life cycle component

The following example shows 2 components from which the first is created from the scratch and the second uses a life cycle framework. Both differ in the way the drawing is invoked. The first component draws 3 times, the second component only once.

NonLifeCycleComponent.as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package lifecycle.lifecycle.introduction {
  import flash.display.Sprite;

  public class NonLifeCycleComponent extends Sprite {
    private var _borderColor : uint = 0x999999;
    private var _backgroundColor : uint = 0xDDDDDD;

    public function NonLifeCycleComponent() {
      draw();
    }

    public function set borderColor(borderColor : uint) : void {
      _borderColor = borderColor;
      draw();
    }

    public function set backgroundColor(backgroundColor : uint) : void {
      _backgroundColor = backgroundColor;
      draw();
    }

    private function draw() : void {
      trace ("DRAW non life cycle component");
      with (graphics) {
        clear();
        lineStyle(1, _borderColor);
        beginFill(_backgroundColor);
        drawRect(0, 0, 100, 100);
      }
    }
  }
}
LifeCycleComponent.as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package lifecycle.lifecycle.introduction {
  import org.as3commons.ui.lifecycle.lifecycle.LifeCycleView;

  public class LifeCycleComponent extends LifeCycleView {
    private var _borderColor : uint = 0x999999;
    private var _backgroundColor : uint = 0xDDDDDD;

    public function LifeCycleComponent() {
      invalidate();
    }

    public function set borderColor(borderColor : uint) : void {
      _borderColor = borderColor;
      invalidate();
    }

    public function set backgroundColor(backgroundColor : uint) : void {
      _backgroundColor = backgroundColor;
      invalidate();
    }
   
    override protected function validate() : void {
      trace ("DRAW life cycle component");
      with (graphics) {
        clear();
        lineStyle(1, _borderColor);
        beginFill(_backgroundColor);
        drawRect(0, 0, 100, 100);
      }
    }
  }
}
ComparisionLCandNLC.as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package lifecycle.lifecycle.introduction {
  import flash.display.Sprite;

  public class ComparisionLCandNLC extends Sprite {
    public function ComparisionLCandNLC() {
      var nlc : NonLifeCycleComponent = new NonLifeCycleComponent();
      nlc.borderColor = 0xAA8888;
      nlc.backgroundColor = 0xEECCCC;
      addChild(nlc).x = 120;

      var lc : LifeCycleComponent = new LifeCycleComponent();
      lc.borderColor = 0xAA8888;
      lc.backgroundColor = 0xEECCCC;
      addChild(lc);
    }
  }
}
ComparisionLCandNLC.swf
DRAW non life cycle component
DRAW non life cycle component
DRAW non life cycle component
DRAW life cycle component

What is a component life cycle?

Regardless if you engage a life cycle framework or not, your component always has its life cycle. The particular life cycle phases and their treatment by a life cycle framework are discussed in this chapter.

  • Creation
  • Initialization
  • Update
  • Drawing and Layouting
  • Disposal

Creation

You create a new component by calling its constructor. Using a life cycle framework, this is the place where the component needs to be registered with the framework.

var button : Button = new Button();

Initialization

After the component instance has been created, the component usually sets up several properties such as sizes, default values for colors, mouse or keyboard event listeners or something else. This might be done right in the constructor of the component but not neccessary.

Often the initial state of a component depends on its position in the display list. A button within a scrollbar is something different than a confirm button in an alert component. In cases like this we might want to listen to the Event.ADDED_TO_STAGE in order to have the parent property of the component set.

// in constructor

public function Button() {
  _width = 200;
  _height = 100;
  _labelText = "Click";
  _backgroundColor = 0xDDDDDD;
}

// from extern

button = new Button();
button.width = 200;
button.height = 100;
button.labelText = "Click";
button.backgroundColor = 0xDDDDDD;

// using init method

public function Button() {
  addEventListener(Event.ADDED_TO_STAGE, init);
}

private function init(event : Event) : void {
  removeEventListener(Event.ADDED_TO_STAGE, added);

  _width = parent.width;
  _height = parent.height;
  _labelText = "Click";
  _backgroundColor = 0xDDDDDD;
}

A life cycle framework will provide you an initialization method that is called after the component has been added to the display list the first time. You do not need to handle the stage events on you own, and you can be sure that the component is in the display list the time the initialization method is called.

Drawing and Layouting

To let the component appear on the screen, the component visuals must be drawn. If this is a nested component, all children should be layouted, too.
Every component will have a place where it is drawn initially. After that is done, the component usually does not need to be redrawn entirely but only in parts depending on properties, that change at runtime.

public function draw() : void {
  with (graphics) {
    beginFill(_backgroundColor);
    drawRect(0, 0, _width, _height);
  }
 
  _label.x = _width - _label.width - 5;
  _skin.x = 5;
}

Drawing is the most expensive functionality of a component. Whenever possible the drawing should not happen redundantly. A common problem in component development is how to manage the drawing efficiently. We don’t want a component to be redrawn right after a single property has been modified, but we still don’t want to externalize the drawing method to be commanded by the user of the component.

// draw immediately

public function set property1(property : *) : void {
  _property1 = property;
  draw();
}

public function set property2(property : *) : void {
  _property1 = property;
  draw();
}

private function draw() : void {
  ...
}

// externalize drawing

public function set property1(property : *) : void {
  _property1 = property;
}

public function set property2(property : *) : void {
  _property1 = property;
}

public function draw() : void {
  ...
}

A life cycle framework solves this by calling a drawing method on your component aynchronously as a result of an internal validation process. This process is scheduled to happen after the current block of code is finished, so it enables the user to set up several properties one by one while the drawing happens later only once. There are different techniques how this can be implemented.

Update

If we want our component to be modifiable at runtime, we need to provide an update mechanism. As discussed in the drawing section, we need some possibility to decouple the property update from the drawing. A life cycle enables you to mark your component as invalid so that its validation method is later called. The component may here execute the drawing.

public function set property1(property : *) : void {
  _property1 = property;
  invalidate();
}

public function set property2(property : *) : void {
  _property1 = property;
  invalidate();
}

override protected function validate() : void {
  draw();
}

private function draw() : void {
  ...
}

Disposal

If you don’t need the component any longer, you want to remove it. You need to remove all foreign references to make the component eligible for garbage collection.

public function dispose() : void {
  _label.removeEventListener("size_changed", labelSizeChanged);
  stage.removeEventListener("mouse_down", mouseDown);
}

Life cycle framework features

Organizing component code

The framework provides methods for all of the mentioned component phases and hence gives your component a well defined structure you can fill in conveniently.

Method invocation order

The framework calls the component methods in a well defined order that is reliable and predictable.

Deferred rendering

The framework schedules visual updates to happen after the current block of code which enables the user to set up several properties on the component one after another without running into performance issues.

Managing nested components

The framework can performantly handle nested components where bidirectional dependencies may occur. To do so, the internal validation process is done in several phases with a different processing order. A top-down phase enables to pass properties from the parent to the child. A bottom-up phase makes sure that a child property is already set, when the parent tries to use it. Typically we use three phases for the validation run.

Validation phase

During the validation the component checks what properties have changed and what exactly needs to be redrawn. The component also may update their child components. When the child component is later processed in this phase, it will already have set all properties that depend on its parent.

Measurement phase

This phase is the place where the component should calculate sizes or properties that are not explicitely set and whose calculation is rather expensive. When the parent component is later processed in this phase, the child properties are already set and the parent can use them.

Why not calculating such sizes or properties right in the first phase? If a parent depends on its child, and this child also depends on its own child, the values of the child2 are not yet know by the time the child1 is processed.

The measurement phase is optional for a component. If there are no properties that need further calculation and the component does not depend on values of their children, the component may leave out this phase.

Rendering phase

Here the component should redraw. There shouldn’t be any properties set during this phase.



Leave a Comment

You have a question or have experienced an issue? Please post it in the forum: http://sibirjak.tenderapp.com/ in order to make the discussion available at a more central place.