Adobe Flex 3 Help

Application coding

The MXML language provides a rich set of controls and classes that you can use to create interactive applications. This richness sometimes can reduce performance. However, there are some techniques that a Flex developer can use to improve the run-time performance of the Flex application.

To measure the effects of the following techniques, you should use the Flex profiler. For more information, see Profiling Flex applications in Using Adobe Flex Builder 3.

Object creation and destruction

Object creation is the task of instantiating all the objects in your application. These objects include controls, components, and objects that contain data and other dynamic information. Optimizing the process of object creation and destruction can result in significant performance gains. Object destruction is the act of reallocating memory for objects after all references to those objects have been removed. This task is carried out by the garbage collector at regular intervals. You can improve the frequency that Flash Player and AIR destroy objects by removing references to objects.

No single task during application initialization takes up the most time. The best way to improve performance is to create fewer objects. You can do this by deferring the instantiation of objects, or changing the order in which they are created to improve perceived performance.

Using ordered creation

You can improve perceived startup time of your Flex application by ordering the creation of containers in the initial view. The default behavior of Flex is to create all containers and their children in the initial view, and then display everything at once. The user cannot interact with the application or see meaningful data until all the containers and their children are created.

In some cases, you can improve the user's initial experience by displaying the components in one container before creating the components in the next container. This process is called ordered creation.

To use ordered creation, you set the creationPolicy property of a container to queued, as the following example shows:

<?xml version="1.0"?>
<!-- optimize/QueuedPanels.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Panel id="panel1" creationPolicy="queued" width="100%" height="33%">
        <mx:Button id="button1a"/>
        <mx:Button id="button1b"/>
    </mx:Panel>

    <mx:Panel id="panel2" creationPolicy="queued" width="100%" height="33%">
        <mx:Button id="button2a"/>
        <mx:Button id="button2b"/>
    </mx:Panel>

    <mx:Panel id="panel3" creationPolicy="queued" width="100%" height="33%">
        <mx:Button id="button3a"/>
        <mx:Button id="button3b"/>
    </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

This adds the container's children to a queue. Flash Player instantiates and displays all of the children within the first container in the queue before instantiating the children in the next container in the queue.

For more information on ordered creation, see Using ordered creation.

Using deferred creation

To improve the start-up time of your application, minimize the number of objects that are created when the application is first loaded. If a user-interface component is not initially visible at start up, create that component only when you need it. This is called deferred creation. Containers that have multiple views, such as an Accordion, provide built-in support for this behavior. You can use ActionScript to customize the creation order of multiple-view containers or defer the creation of other containers and controls.

To use deferred creation, you set the value of a component's creationPolicy property to all, auto, or none. If you set it to none, Flex does not instantiate a control's children immediately, but waits until you instruct Flex to do so. In the following example, the children of the VBox container are not be instantiated when the application is first loaded, but only after the user clicks the button:

<?xml version="1.0"?>
<!-- optimize/CreationPolicyNone.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script><![CDATA[

        private function createButtons(e:Event):void {
            myVBox.createComponentsFromDescriptors();
        }

    ]]></mx:Script>

    <mx:Panel title="VBox with Repeater">
        <mx:VBox id="myVBox" height="100" width="125" creationPolicy="none">
            <mx:Button id="b1" label="Hurley"/>
            <mx:Button id="b2" label="Jack"/>
            <mx:Button id="b3" label="Sawyer"/>
        </mx:VBox>
    </mx:Panel>
    
    <mx:Button id="myButton" click="createButtons(event)" label="Create Buttons"/>

</mx:Application>

The executing SWF file for the previous example is shown below:

You call methods such as createComponentFromDescriptor() and createComponentsFromDescriptor() on the container to instantiate its children at run time. For more information on using deferred instantiation, see Using deferred creation.

Destroying unused objects

Flash Player provides built-in garbage collection that frees up memory by destroying objects that are no longer used. To ensure that the garbage collector destroys your unused objects, remove all references to that object, including the parent's reference to the child.

For more information about garbage collection, see About garbage collection in Using Adobe Flex Builder 3.

On containers, you can call the removeChild() or removeChildAt() method to remove references to child controls that are no longer needed. The following example removes references to button instances from the myVBox control:

<?xml version="1.0"?>
<!-- optimize/DestroyObjects.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script><![CDATA[
        private function destroyButtons(e:Event):void {
            myVBox.removeChild(b1);
            myVBox.removeChild(b2);
            myVBox.removeChild(b3);
        }
    ]]></mx:Script>

    <mx:Panel title="VBox with Repeater">
        <mx:VBox id="myVBox" height="100" width="125">
            <mx:Button id="b1" label="Hurley"/>
            <mx:Button id="b2" label="Jack"/>
            <mx:Button id="b3" label="Sawyer"/>
        </mx:VBox>
    </mx:Panel>
    
    <mx:Button id="myButton2" click="destroyButtons(event)" label="Destroy Buttons"/>

</mx:Application>

The executing SWF file for the previous example is shown below:

You can clear references to unused variables by setting them to null in your ActionScript; for example:

myDataProvider = null

To ensure that destroyed objects are garbage collected, you must also remove event listeners on them by using the removeEventListener() method, as the following example shows:

<?xml version="1.0"?>
<!-- optimize/RemoveListeners.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp(event)">
    <mx:Script><![CDATA[
        private function initApp(e:Event):void {
            b1.addEventListener("click",myClickHandler);
            b2.addEventListener("click",myClickHandler);
            b3.addEventListener("click",myClickHandler);
        }

        private function destroyButtons(e:Event):void {
            b1.removeEventListener("click",myClickHandler);
            b2.removeEventListener("click",myClickHandler);
            b3.removeEventListener("click",myClickHandler);

            myVBox.removeChild(b1);
            myVBox.removeChild(b2);
            myVBox.removeChild(b3);
        }
        
        private function myClickHandler(e:Event):void {
            // Do something here.
        }
    ]]></mx:Script>

    <mx:Panel title="VBox with Repeater">
        <mx:VBox id="myVBox" height="100" width="125">
            <mx:Button id="b1" label="Hurley"/>
            <mx:Button id="b2" label="Jack"/>
            <mx:Button id="b3" label="Sawyer"/>
        </mx:VBox>
    </mx:Panel>
    
    <mx:Button id="myButton" click="destroyButtons(event)" label="Destroy Buttons"/>

</mx:Application>

The executing SWF file for the previous example is shown below:

You cannot call the removeEventListener() method on an event handler that you added inline. In the following example, you cannot call removeEventListener() on b1's click event handler, but you can call it on b2's and b3's event handlers:

<?xml version="1.0"?>
<!-- optimize/RemoveSomeListeners.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp(event)">
    <mx:Script><![CDATA[
        private function initApp(e:Event):void {
            b2.addEventListener("click",myClickHandler);
            b3.addEventListener("click",myClickHandler);
        }

        private function destroyButtons(e:Event):void {
            b2.removeEventListener("click",myClickHandler);
            b3.removeEventListener("click",myClickHandler);

            myVBox.removeChild(b1);
            myVBox.removeChild(b2);
            myVBox.removeChild(b3);
        }
        
        private function myClickHandler(e:Event):void {
            // Do something here.
        }
    ]]></mx:Script>

    <mx:Panel title="VBox with Repeater">
        <mx:VBox id="myVBox" height="100" width="125">
            <mx:Button id="b1" label="Hurley" click="myClickHandler(event)"/>
            <mx:Button id="b2" label="Jack"/>
            <mx:Button id="b3" label="Sawyer"/>
        </mx:VBox>
    </mx:Panel>
    
    <mx:Button id="myButton" click="destroyButtons(event)" label="Destroy Buttons"/>

</mx:Application>

The executing SWF file for the previous example is shown below:

The weakRef parameter to the addEventListener() method provides you with some control over memory resources for listeners. A strong reference (when weakRef is false) prevents the listener from being garbage collected. A weak reference (when weakRef is true) does not. The default is false.

For more information about the removeEventListener() method, see Using Events in the Adobe Flex 3 Developer Guide.

Using styles

You use styles to define the look and feel of your Flex applications. You can use them to change the appearance of a single component, or apply them globally. Be aware that some methods of applying styles are more expensive than others. You can increase your application's performance by changing the way you apply styles.

For more information about using styles, see Using Styles and Themes in the Adobe Flex 3 Developer Guide.

Loading stylesheets at run time

You can load stylesheets at run time by using the StyleManager. These style sheets take the form of SWF files that are dynamically loaded while your Flex application runs.

By loading style sheets at run time, you can load images (for graphical skins), fonts, type and class selectors, and programmatic skins into your Flex application without embedding them at compile time. This lets skins and fonts be partitioned into separate SWF files, away from the main application. As a result, the application's SWF file size is smaller, which reduces the initial download time. However, the first time a run-time style sheet is used, it takes longer for the styles and skins to be applied because Flex must download the necessary CSS-based SWF file.

For more information, see the Adobe Flex 3 Developer Guide.

Reducing calls to the setStyle() method

Run-time cascading styles are very powerful, but use them sparingly and in the correct context. Calling the setStyle() method can be an expensive operation because the call requires notifying all the children of the newly-styled object. The resulting tree of children that must be notified can be quite large.

A common mistake that impacts performance is overusing or unnecessarily using the setStyle() method. In general, you only use the setStyle() method when you change styles on existing objects. Do not use it when you set up styles for an object for the first time. Instead, set styles in an <mx:Style> block, as style properties on the MXML tag, through an external CSS style sheet, or as global styles.

Some applications must call the setStyle() method during the application or object instantiation. If this is the case, call the setStyle() method early in the instantiation phase. Early in the instantiation phase means setting styles from the component or application's preinitialize event, instead of the initialize or creationComplete event. By setting the styles as early as possible during initialization, you avoid unnecessary style notification and lookup.

If you programmatically create a component and want to set styles on that component, call the setStyle() method before you attach it to the display list with a call to the addChild() method, as the following example shows:

<?xml version="1.0"?>
<!-- optimize/CreateStyledButton.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp(event)">
    <mx:Script><![CDATA[
        import mx.controls.Button;
    
        public function initApp(e:Event):void {
            var b:Button = new Button();
            b.label="Click Me";
            b.setStyle("color", 0x00CCFF);
            panel1.addChild(b);
        }
    ]]></mx:Script>
        
    <mx:Panel id="panel1"/>
    
</mx:Application>

The executing SWF file for the previous example is shown below:

Setting global styles

Changing global styles (changing a CSS ruleset that is associated with a class or type selector) at run time is an expensive operation. Any time you change a global style, Flash Player must perform the following actions:

  • Traverse the entire application looking for instances of that control.
  • Check all the control's children if the style is inheriting.
  • Redraw that control.

The following example globally changes the Button control's color style property:

<?xml version="1.0"?>
<!-- optimize/ApplyGlobalStyles.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp(event)">
    <mx:Script><![CDATA[
        public function initApp(e:Event):void {
            StyleManager.getStyleDeclaration("Button").setStyle("color", 0x00CCFF);
        }
    ]]></mx:Script>
        
    <mx:Panel id="panel1">
        <mx:Button id="b1" label="Click Me"/>
        <mx:Button id="b2" label="Click Me"/>
        <mx:Button id="b3" label="Click Me"/>
    </mx:Panel> 
    
</mx:Application>

The executing SWF file for the previous example is shown below:

If possible, set global styles at authoring time by using CSS. If you must set them at run time, try to set styles by using the techniques described in Reducing calls to the setStyle() method.

Calling the setStyleDeclaration() and loadStyleDeclarations() methods

The setStyleDeclaration() method is computationally expensive. You can prevent Flash Player from applying or clearing the new styles immediately by setting the update parameter to false.

The following example sets new class selectors on different targets, but does not trigger the update until the last style declaration is applied:

<?xml version="1.0"?> 
<!-- styles/SetStyleDeclarationExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
  <mx:Script><![CDATA[ 
        import mx.styles.StyleManager;

        private var myButtonStyle:CSSStyleDeclaration = new CSSStyleDeclaration('myButtonStyle');
        private var myLabelStyle:CSSStyleDeclaration = new CSSStyleDeclaration('myLabelStyle');
        private var myTextAreaStyle:CSSStyleDeclaration = new CSSStyleDeclaration('myTextAreaStyle');

        private function initApp():void {
            myButtonStyle.setStyle('color', 'blue');
            myLabelStyle.setStyle('color', 'blue');
            myTextAreaStyle.setStyle('color', 'blue');
        }

        private function applyStyles():void {
            StyleManager.setStyleDeclaration("Button", myButtonStyle, false);
            StyleManager.setStyleDeclaration("Label", myLabelStyle, false);
            StyleManager.setStyleDeclaration("TextArea", myTextAreaStyle, true);
        }
  ]]></mx:Script>

    <mx:Button id="myButton" label="Click Me" click="applyStyles()"/>
    <mx:Label id="myLabel" text="This is a label"/>
    <mx:TextArea id="myTextArea" text="This is a TextArea"/>

</mx:Application>

The executing SWF file for the previous example is shown below:

When you pass false for the update parameter, Flash Player stores the selector but does not apply the style. When you pass true for the update parameter, Flash Player recomputes the styles for every visual component in the application.

The loadStyleDeclarations() method is similarly computationally expensive. When you load a new style sheet, this method triggers an update to the display list by default. You can prevent Flash Player from applying or clearing the new style sheets immediately by setting the update parameter to false. When you chain calls to loadStyleDeclarations() methods, set the update parameter to false for all calls except the last one.

Working with containers

Containers provide a hierarchical structure that lets you control the layout characteristics of container children. You can use containers to control child sizing and positioning, or to control navigation among multiple child containers.

When you develop your Flex application, try to minimize the number of containers that you use. This is because most containers provide relative sizing and positioning, which can be resource-intensive operations, especially when an application first starts.

One common mistake is to create a container that contains a single child. Sometimes having a single child in a container is necessary, such as when you use the container's padding to position the child. But try to identify and remove containers such as these that provide no real functionality. Also keep in mind that the root of an MXML component does not need to be a container.

Another sign of possibly too many containers is when you have a container nested inside another container, where both the parent and child containers have the same type (for example, HBoxes).

Minimizing container nesting

It is good practice to avoid deeply nested layouts when possible. For simple applications, if you have nested containers more than three levels deep, you can probably produce the same layout with fewer levels of containers. Deep nesting can lead to performance problems. For larger applications, deeper nesting might be unavoidable.

When you nest containers, each container instance runs measuring and sizing algorithms on its children (some of which are containers themselves, so this measuring procedure can be recursive). When the layout algorithms have processed, and the relative layout values have been calculated, Flash Player draws the complex collection of objects comprising the view. By eliminating unnecessary work at object creation time, you can improve the performance of your application.

Using Grid containers

A Grid container is useful for aligning multiple objects. When you use Grid containers, however, you introduce additional levels of containers with the GridItem and GridRow controls. In many cases, you can achieve the same results by using the VBox and HBox containers, and these containers use fewer levels of nesting.

Using layout containers

You can sometimes improve application start-up time by using Canvas containers, which perform absolute positioning, instead of relative layout containers, such as the Form, HBox, VBox, Grid, and Tile containers.

Canvas containers are the only containers that let you specify the location of their child controls by default. All other containers are relative containers by default, which means that they lay everything out relative to other components in the container. You can make Application and Panel containers do absolute positioning.

Canvas containers eliminate the layout logic that other containers use to perform automatic positioning of their children at startup, and replace it with explicit pixel-based positioning. When you use a Canvas container, you must remember to set the x and y positions of all of its children. If you do not set the x and y positions, the Canvas container's children lay out on top of each other at the default x, y coordinates (0,0).

The canvas container is not always more efficient than other containers, however, because it must measure itself to make sure that it is large enough to contain its children. Applications that use canvases typically contain a much flatter containment hierarchy. As a result, using canvas containers can lead to less nesting and fewer overall containers, which improves performance.

Canvas containers support constraints, which means that if the container changes size, the children inside the container move with it.

Using absolute sizing

Writing object widths and heights into the code can save time because the Flex layout containers do not have to calculate the size of the object at run time. By specifying container or control widths or heights, you lighten the relative layout container's processing load and subsequently decrease the creation time for the container or control. This technique works with any container or control.

Improving effect performance

Effects let you add animation and motion to your application in response to user or programmatic action. For example, you can use effects to cause a dialog box to bounce slightly when it receives focus, or to slowly fade in when it becomes visible.

Effects can be one of the most processor-intensive tasks performed by a Flex application. Use the techniques described in this section to improve the performance of effects. For more information, see Using Behaviors in the Adobe Flex 3 Developer Guide.

Increasing effect duration

Increase the duration of your effect with the duration property. Doing this spreads the distinct, choppy stages over a longer period of time, which lets the human eye fill in the difference for a smoother effect.

Hiding parts of the target view

Make parts of the target view invisible when the effect starts, play the effect, and then make those parts visible when the effect has completed. To do this, you add logic in the effectStart and effectEnd event handlers that controls what is visible before and after the effect.

When you apply a Resize effect to a Panel container, for example, the measurement and layout algorithm for the effect executes repeatedly over the duration of the effect. When a Panel container has many children, the animation can be jerky because Flex cannot update the screen quickly enough. Also, resizing one Panel container often causes other Panel containers in the same view to resize.

To solve this problem, you can use the Resize effect's hideChildrenTargets property to hide the children of Panel containers while the Resize effect is playing. The value of the hideChildrenTargets property is an Array of Panel containers that should include the Panel containers that resize during the animation. When the hideChildrenTargets property is true, and before the Resize effect plays, Flex iterates through the Array and hides the children of each of the specified Panel containers.

Avoiding bitmap-based backgrounds

Designers often give their views background images that are solid colors with gradients, slight patterns, and so forth. To ease what Flash Player redraws during an effect, try using a solid background color for your background image. Or, if you want a slight gradient instead of a solid color, use a background image that is a SWF or SVG file. These are easier for Flash Player to redraw than standard JPG or PNG files.

Suspending background processing

To improve the performance of effects, you can disable background processing in your application for the duration of the effect by setting the suspendBackgroundProcessing property of the Effect to true. The background processing that is blocked includes component measurement and layout, and responses to data services for the duration of the effect.

Using the cachePolicy property

An effect can use bitmap caching in Flash Player to speed up animations. An effect typically uses bitmap caching when the target component's drawing does not change while the effect is playing.

The cachePolicy property of UIComponents controls the caching operation of a component during an effect. The cachePolicy property can have the following values:

CachePolicy.ON 

Specifies that the effect target is always cached.



CachePolicy.OFF 

Specifies that the effect target is never cached.



CachePolicy.AUTO 

Specifies that Flex determines whether the effect target should be cached. This is the default value.



The cachePolicy property is useful when an object is included in a redraw region but the object does not change. For more information about redraw regions, see Understanding redraw regions.

The cachePolicy property provides a wrapper for the cacheAsBitmap property. For more information, see Using the cacheAsBitmap property.

Improving rendering speed

The actual rendering of objects on the screen can take a significant amount of time. Improving the rendering times can dramatically improve your application's performance. Use the techniques in this section to help improve rendering speed. In addition, use the techniques described in the previous section, Improving effect performance, to improve effect rendering speed.

Setting movie quality

You can use the quality property of the wrapper's <object> and <embed> tags to change the rendering of your Flex application in Flash Player. Valid values for the quality property are low, medium, high, autolow, autohigh, and best. The default value is best.

The low setting favors playback speed over appearance and never uses anti-aliasing. The autolow setting emphasizes speed at first but improves appearance whenever possible. The autohigh setting emphasizes playback speed and appearance equally at first, but sacrifices appearance for playback speed if necessary. The medium setting applies some anti-aliasing and does not smooth bitmaps. The high setting favors appearance over playback speed and always applies anti-aliasing. The best setting provides the best display quality and does not consider playback speed. All output is anti-aliased and all bitmaps are smoothed.

For information on these settings, see About the object and embed tags.

Understanding redraw regions

A redraw region is the region around an object that must be redrawn when that object changes. Everything in a redraw region is redrawn during the next rendering phase after an object changes. The area that Flash Player redraws includes the object, and any objects that overlap with the redraw region, such as the background or the object's container.

You can see redraw regions at run time in the debugger version of Flash Player by selecting View > Show Redraw Regions in the player's menu. When you select this option, the debugger version of Flash Player draws red rectangles around each redraw region while the application runs.

By looking at the redraw regions, you can get a sense of what is changing and how much rendering is occurring while your application runs. Flash Player sometimes combines the redraw regions of several objects into a single region that it redraws. As a result, if your objects are spaced close enough together, they might be redrawn as part of one region, which is better than if they are redrawn separately. If the number of regions is too large, Flash Player might redraw the entire screen.

Using the cacheAsBitmap property

To improve rendering speeds, make careful use of the cacheAsBitmap property. You can set this property on any UIComponent.

When you set the cacheAsBitmap property to true, Flash Player stores a copy of the initial bitmap image of an object in memory. If you later need that object, and the object's properties have not changed, Flash Player uses the cached version to redraw the object. This can be faster than using the vectors that make up the object.

Setting the cacheAsBitmap property to true can be especially useful if you use animations or other effects that move objects on the screen. Instead of redrawing the object in each frame during the animation, Flash Player can use the cached bitmap.

The downside is that changing the properties of objects that are cached as bitmaps is more computationally expensive. Each time you change a property that affects the cached object's appearance, Flash Player must remove the old bitmap and store a new bitmap in the cache. As a result, only set the cacheAsBitmap property to true for objects that do not change much.

Enable bitmap caching only when you need it, such as during the duration of an animation, and only on a few objects at a time because it can be a memory-intensive operation. The best approach might be to change this property at various times during the object's life cycle, rather than setting it once.

Using filters

To improve rendering speeds, do not overuse filters such as DropShadowFilter. The expense of the filter is proportional to the number of pixels in the object that you are applying the filter to. As a result, it is best to use filters on smaller objects.

Using device text

Mixing device text and vector graphics can slow rendering speeds. For example, a DataGrid control that contains both text and graphics inside a cell will be much slower to redraw than a DataGrid that contains just text.

Using clip masks

Using the scrollRect and mask properties of an object are expensive operations. Try to minimize the number of times you use these properties.

Using large data sets

You can minimize overhead when working with large data sets.

Paging

When you use a DataService class to get your remote data, you might have a collection that does not initially load all of its data on the client. You can prevent large amounts of data from traveling over the network and slowing down your application while that data is processed using paging. The data that you get incrementally is referred to as paged data, and the data that has not yet been received is pending data.

Paging data using the DataService class provides the following benefits:

  • Maximum message size on the destination can be configured.
  • If size exceeds the maximum value, multiple message batches are used.
  • Client reassembles separate messages.
  • Asynchronous data paging across the network.
  • User interface elements can display portions of the collection without waiting for the entire collection to load.

For more information, see Using Data Providers and Collections in the Adobe Flex 3 Developer Guide.

Disabling live scrolling

Using a DataGrid control with large data sets might make it slow to scroll when using the scrollbar. When the DataGrid displays newly visible data, it calls the getItemAt() method on the data provider.

The default behavior of a DataGrid is to continuously update data when the user is scrolling through it. As a result, performance can degrade if you just simply scroll through the data on a DataGrid because the DataGrid is continuously calling the getItemAt() method. This can be a computationally expensive method to call.

You can disable this live scrolling so that the view is only updated when the scrolling stops by setting the liveScrolling property to false.

The default value of the liveScrolling property is true. All subclasses of ScrollControlBase, including TextArea, HorizontalList, TileList, and DataGrid, have this property.

Dynamically repeating components

There are relative benefits of using List-based controls (rather than the Repeater control) to dynamically repeat components. If you must use the Repeater, however, there are techniques for improving the performance of that control.

Comparing List-based controls to the Repeater control

To dynamically repeat components, you can choose between the Repeater or List-based controls, such as HorizontalList, TileList, or List. To achieve better performance, you can often replace layouts you created with a Repeater with the combination of a HorizontalList or TileList and an item renderer.

The Repeater object is useful for repeating a small set of simple user interface components, such as RadioButton controls and other controls typically used in Form containers. You can use the HorizontalList, TileList, or List control when you display more than a few repeated objects.

The HorizontalList control displays data horizontally, similar to the HBox container. The HorizontalList control always displays items from left to right. The TileList control displays data in a tile layout, similar to the Tile container. The TileList control provides a direction property that determines if the next item is down or to the right. The List control displays data in a single vertical column.

Unlike the Repeater object, which instantiates all objects that are repeated, the HorizontalList, TileList, and List controls only instantiate what is visible in the list. The Repeater control takes a data provider (typically an Array) that creates a new copy of its children for each entry in the Array. If you put the Repeater control's children inside a container that does not use deferred instantiation, your Repeater control might create many objects that are not initially visible.

For example, a VBox container creates all objects within itself when it is first created. In the following example, the Repeater control creates all the objects whether or not they are initially visible:

<?xml version="1.0"?>
<!-- optimize/VBoxRepeater.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:Script><![CDATA[
        import mx.collections.ArrayCollection;
    
        [Bindable]
        public var imgList:ArrayCollection = new ArrayCollection([
            {img:"../assets/butterfly.gif"},
            {img:"../assets/butterfly-gray.gif"},
            {img:"../assets/butterfly-silly.gif"}
        ]);     

    ]]></mx:Script>

    <mx:Panel title="VBox with Repeater">
        <mx:VBox height="150" width="250">
            <mx:Repeater id="r" dataProvider="{imgList}">
                <mx:Image source="../assets/{r.currentItem.img}"/>
            </mx:Repeater>
        </mx:VBox>
    </mx:Panel>

</mx:Application>

The executing SWF file for the previous example is shown below:

If you use a List-based control, however, Flex only creates those controls in the list that are initially visible. The following example uses the List control to create only the image needed for rendering:

<?xml version="1.0"?>
<!-- optimize/ListItems.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
   <mx:Script><![CDATA[
        import mx.collections.ArrayCollection;
    
        private static var birdList:Array = ["../assets/butterfly.gif","../assets/butterfly-gray.gif","../assets/butterfly-silly.gif"];
        [Bindable]
        private var birdListAC:ArrayCollection = new ArrayCollection(birdList);

        private function initCatalog():void {
            birdlist.dataProvider = birdListAC;
        }

    ]]></mx:Script>

    <mx:Panel title="List">
        <mx:List id="birdlist" rowHeight="150" width="250" rowCount="1" itemRenderer="mx.controls.Image" creationComplete="initCatalog()">
        </mx:List>  
    </mx:Panel>
</mx:Application>

The executing SWF file for the previous example is shown below:

Using the Repeater control

When using a Repeater control, keep the following techniques in mind:

  • Avoid repeating objects that have clip masks because using clip masks is a resource- intensive process.
  • Ensure that the containers used as the children of the Repeater control do not have unnecessary container nesting and are as small as possible. If a single instance of the repeated view takes a noticeable amount of time to instantiate, repeating makes it worse. For example, multiple Grid containers in a Repeater object do not perform well because Grid containers themselves are resource-intensive containers to instantiate.
  • Set the recycleChildren property to true. The recycleChildren property is a Boolean value that, when set to true, binds new data items into existing Repeater children, incrementally creates children if there are more data items, and destroys extra children that are no longer required.

    The default value of the recycleChildren property is false to ensure that you do not leave stale state information in a repeated instance. For example, suppose you use a Repeater object to display photo images and each Image control has an associated NumericStepper control for how many prints you want to order. Some of the state information, such as the image, comes from the dataProvider property. Other state information, such as the print count, is set by user interaction. If you set the recycleChildren property to true and page through the photos by incrementing the Repeater object's startingIndex value, the Image controls bind to the new images, but the NumericStepper control maintains the old information. Use recycleChildren="false" only if it is too cumbersome to reset the state information manually, or if you are confident that modifying your dataProvider property should not trigger a recreation of the Repeater object's children.

    Keep in mind that the recycleChildren property has no effect on a Repeater object's speed when the Repeater object loads the first time. The recycleChildren property improves performance only for subsequent changes to the Repeater control's data provider. If you know that your Repeater object creates children only once, you do not have to use the recycleChildren property or worry about the stale state situation.