Optimizing the Flex Runtime

2011 January 10
by admin

Introduction

The Flex Framework provides a great platform for developing Rich Internet Applications. Some of the best features of the framework include the ability to automate code (MXML, Binding, States), the vector graphics support (FXG, GraphicElements, native graphics class), and the Rich component library. However, a lack of understanding of the Flash Player execution model, the flex component life cycle, or the vast component library (spark and halo) can lead to some extremely heavy run-time considerations. Furthermore, depending on the compiler to generate code can lead to heavier components and substantially larger swf sizes. This post is based on a number of articles and presentations that I have studied and will provide reference for at the end. However, it was based primarily on a presentation given by Ryan Frishberg at Adobe MAX. I recreated the Keynote as well as the examples within his presentation and have attached them to this blog post. This post is not meant to be exaustive or even touch on 1/2 of the ways you can optimize your applications. Rather, it should be thought of as a quick reference to broader topics with links to more in-depth studies on Optimization.

The Flash Player execution model

The first thing that I think every Flex/Flash developer should understand is how the Flash Player renders things. It uses the concept of frames to process ActionScript code and then update the visual appearance of the screen to the user (a default of 24 times per second in Flex). The use of frames allows developers to easily add fun effects and animations to any Application–one of the things that makes Flex so attractive. However, one of the things that few developers understand is that ActionScript is processed within a single frame unless otherwise specified. This means that complex ActionScript or Graphics manipulation will cause longer frame lags and result in a choppy or frozen visual display. Let’s analyze a diagram from Ted Patrick displaying this process a little better:

Image taken from http://www.craftymind.com/2008/04/18/updated-elastic-racetrack-for-flash-9-and-avm2/

Notice from the diagram that heavy code execution or graphical rendering will cause a frame to stretch out. Here are a few recommendations for optimizing the user experience by decreasing frame lags:

  • Don’t bloat the client with server side logic – There are a lot of things that belong on the server so that they don’t slow down the display. When people first start working in Flex they become excited about the object oriented nature of the language and the ability to do so many things. If people were working in an AJAX project, they would automatically put a lot of logic in the server because of the superior nature of server side language. Please resist the temptation to put complex computations in ActionScript and keep them where they belong.
  • Be aware of frame execution time – It is really important to know how much time you have to process your code and maintain a good user experience. The default frame rate within flex is 24 fps. This means that you have 40 milliseconds to process all of your code and change the display. If a process is going to take more time then try to split it up in more than one frame. This is a process called pseudo threading. In Flex, you can use the callLater() function to add logic to a queue that will be called within the next frame. To break logic up into multiple frames, you can create your own queue that is triggered on an Event.ENTER_FRAME event. For a good post on pseudo threading refer to Alex Harui’s comments at this link.

The Flex Component Life Cycle

Now that we have discussed the concept of frames within the Flash Player let’s dive into how they are used within Flex. The Component Life Cycle is a series of events and function calls made by the Flex Framework to ensure that logical chunks of data are processed synchronously and only once per frame. It uses validation triggers to call methods within each component in a continuous loop. A lack of understanding of the process can lead to validating a hierarchy of components multiple times per frame instead of just once. The ramifications of such an action can lead to heavy frames and an unpleasant user experience. Please refer to the table below for a brief list of the different functions in this process and what should be placed in them. Each method can be overridden by subclasses and modified as needed. NOTE: None of the methods should be called directly. Instead, the methods can be invoked by setting their setting their invalidation flags as specified.

Method Invoke Method Description
createChildren() Only called once This is the first method called in the flex event stack and is where you will want to add any children of the component. If you are using mxml this method will be automated by the compiler.
commitProperties() invalidateProperties() Commit Properties is called on creation, every time a new child is added, and when it is flagged with an invalidate method. You will want to override this method to set the properties of your DisplayObjects. If you set the properties of a Display Object directly (e.g. label.text) outside of commitProperties you may force validation to occur more than once.
measure() invalidateSize() If you have extended UIComponent then you will need to write your own measure function. However, if you are creating a component from another container, (e.g. HGroup) it will provide it’s own measuring. HINT: An easy way to measure your component is to set the measuredWidth and measuredHeight to the measuredWidths and measuredHeights of child components.
updateDisplayList() invalidateDisplayList() This is where you will move child components (set x and y coordinates) and draw anything to the stage. If you have extended UIComponent you will need to call setActualSize() on each component or they won’t show up.

Spark vs. Halo Components

The Spark Library was built with optimization in mind. We would see immediate performance gains by simply switching everything over to Spark because of the new modular design. For example, a spark Group is extremely light weight compared to a flex 3 Container because logical portions such as skinning, layout, and scroll bars can be added as needed instead of being inherited by default. When using a component, look first to the spark library to see if there is a matching spark component before defaulting to the Halo component.

Here are a couple other recommendations when using Spark components:

  • MX Navigator’s (e.g. ViewStack, TabNavigator, Accordion) only accept children of type INavigatorContent. The only container within the spark library that implements this interface is the NavigatorContent. Please use the NavigatorContent Container instead of defaulting to the old halo containers.
  • If you need to skin a container then use a container that extends from SkinnableContainerBase such as SkinnableContainer or SkinnableDataContainer. A Group does not support skinning in order to be as light as possible. If you do not need the skinning behavior then use a Group. Always use the lightest component possible.

Defer instantiation of components

When developing within the Flash Player we must be continuously mindful of Frames. Remember, we only have 40 milliseconds (in a 24 fps application) to render data to the screen. If we attempt to render too much at once, frames will be stretched out and our application will appear to be frozen to the user. I have seen some applications where progress bars will stop for 4 or more seconds to render all data to the screen. Using our image of the elastic racetrack, this would be the concept of Heavy Rendering. One of the best ways to mitigate the risk of “Heavy Rendering” is to minimize the amount of visual components added to the stage at one time. There are three ways to defer instantiation of components within flex:

  1. Use a Navigator Container – Navigator Containers such as ViewStack and TabNavigator have a property called creationPolicy that will add the children to the stage as necessary if set to true.
  2. Use states – States will only add components to the a container when and if the states are set. They will also remove those components when you exit that state. NOTE: states are just a way of automating ActionScript so you could easily provide this logic on your own.
  3. Write custom ActionScript – Use the addElement, addElementAt, removeElement, and removeElementAt methods to add and remove children via ActionScript as needed.

Utilize Virtual Layouts for large data sets

Another way to delay the instantiation of components is to use a Virtual Layout Container such as a List. In a Virtual Layout, only the visible components in a Viewport are created and then they are recycled as you scroll.  To use an example, lets assume that you wanted to create a Viewport with 1000 columns and 1000 rows.  If you tried to create each child in the ViewPort you would have to add 1,000,000 children (1000 * 1000) to the stage.  Obviously, this would have some extreme performance considerations in the Flash Player.  In fact, the Flash Player would probably crash or throw up an ActionScript error.  On the other hand, utilizing a Vitual Layout you would only create the visual children.  Please refer to the diagram below for a better depiction of this process.

Image taken from Ryan Frishberg’s Presentation

From the diagram above, the Viewport would only create 25 children at one time (5 * 5) instead of all million components.  It would then recycle the cells (ItemRenderer’s) as you scroll to the right or left.  The flex components that have been optimized with this virtual layout in mind include the following:

  • DataGroup – The lightest of all virtual containers. Does not support skinning, native hover states, or add the drag and drop functionality of a List. Should be used when you want to create a simple List or Grid of repeatable items.
  • SkinnableDataGroup – Exactly like DataGroup except that it supports skinning. Should be used to create simple Lists or Grids of repeatable items when a skin is needed.
  • List – Extends from SkinnableDataContainer and adds automatic hover and selected state indicators to items. Adds native drag and drop functionality without the need to add through code. Supports Data Virtualization by default. Should be used when extra functionality of the list will be used by child components.
  • DataGrid – Perfect for displaying complex data sets. Adds column headers, native item renderers, item editors, resizable columns, data virtualization, etc. This component is key to creating optimized data centric flex applications. As of flex sdk 4.5, there is a new spark DataGrid. If you are using 4.0 or 4.1 you will have to use the old halo DataGrid.

NOTE: DataGroup and SkinnableDataGroup do not support Virtualization by default. This needs to be added as an attribute of the layout object. In the following code example, notice the useVirtualLayout attribute:

1
2
3
4
5
<s:DataGroup itemRenderer="com.components.CustomRenderer" dataProvider="{myDataProvider}" width="100%">
     <s:layout>
          <s:VerticalLayout gap="0" useVirtualLayout="true" />
     </s:layout>
</s:DataGroup>

Optimize Custom ItemRenderer’s

Virtual Layouts alone will not create an optimized user experience. In fact, heavy or inefficient Item Renderers can create just the opposite. Remember the children (ItemRenerers) of a ViewPort are reused and reinitialized as you scroll. Therefore, inefficiency will cause a heavy user experience over and over as you scroll through the ViewPort. Here are some recommendations for overcoming common the most common problems:

  • Don’t use states – States are a great convenience to developers because they automate a lot of code and add a lot of logic to components. However, states also come with a cost as they add a ton of code. Please create your own state logic when possible within Item Renderers.
  • Stay away from Binding – Binding is another convenience within the Flex Framework that automates a lot of code. Behind the scenes, Binding is nothing more than an event protocol where event dispatchers and listeners are automated. This is a process that could add up to 2000 lines of code to a component for just one Binding. When inside an ItemRenderer please override the set data function instead of using Binding. For example:
    1
    2
    3
    4
    5
    override public function set data(value:Object):void
    {
         super.data = value;
         label.text = data.label;
    }
  • Use constraint and static layouts – One of the main ways that people create non-optimized code within ItemRenderer’s is by embedding a bunch of containers. For example, an HGroup with two VGroups (or HBox with two VBox’s) as children. A better practice is to use a Group (or SkinnableGroup) with a basic layout and either hard code x and y’s or use a constraint based layout. For more information on using constraint based layouts please refer to adobe’s site.
  • Use lightweight children – Finally, remember to always use the lightest children possible. For example, instead of using Image use BitmapImage. And instead of using RichText use Label. Obviously, there are cases where the heavier components are needed but use them sparingly.

Use FXG and Graphic Elements

In Flex 3, all children of a container had to be of type UIComponent. This Class provides a lot of the dynamic behaviors needed by custom classes within Flex. For example, it provides all methods of the component lifecycle as well as many properties shared among objects. However, for simple vector graphics classes, UIComponent is a lot heavier than needed. Flex 4 added the ability to add simple graphics known as FXG to containers that only have visual logic. FXG is an XML based markup that is very similar to SVG in syntax. It can be implemented either in MXML using the spark namespace or by generating an external XML file. Notice that FXG added through an external file is compiled in and cannot be changed at runtime. If you need to ability to change the graphic then it should be added through MXML. Also note that while you could hand write your own FXG, it is a lot easier to use an image manipulation tool like Illustrator to automate your FXG. In terms of weight, graphics should be used in the following order:

  1. FXG – External XML files. FXG is compiled into an application and cannot be changed at runtime
  2. Graphic Element (Runtime FXG) – Use FXG tags with spark namespace withing MXML. This is a little bit heavier than native FXG because of the runtime considerations.
  3. Custom Drawing with UIComponent – Extend from UIComponent and draw graphics using ActionScript when you need custom interactions. For example, if you need Roll-over or roll out states.

Other Performance Considerations

Here is are some other quick performance tricks–some of which came came straight from Ryan Frishberg’s presentation:

  • ArrayList vs ArrayCollection – An ArrayList is lighter (the parent of) than an ArrayCollection. You should use it as the source of a List or DataGrid when you don’t need sorting or filtering capabilities.
  • Resetting an Array – Creating a new Array in memory is a lot more expensive than resetting the array. Instead of using the syntax:
    1
            arr1 = new Array();

    use this syntax

    1
           arr1.length = 0;
  • Deep Cloning – There isn’t always a need to deep clone an object and especially not an ArrayCollection. The last place that I worked had a really bad practice of deep cloning every array to ensure that one view wouldn’t mess up the other view. An ArrayCollection is simply a wrapper for an Array Object. Therefore, making changes to one ArrayCollection (e.g. filter or sort function) won’t mess up the other ArrayCollection. You can create a shallow clone of an object by using the following code:
    1
         var newAC:ArrayCollection = new ArrayCollection( oldAC.source );

    Notice that the underlying source array stays the same. Filters and sort functions will be applied to the wrapper and not the underlying source. Therefore, they can be completely different. You may want to deep clone if the properties of the child objects will be changed.

Resources

Performance Tips and Tricks for Flex and Flash Development
Ryan Frishberg’s Keynote (Re-created from max video)
Flash Elastic Racetrack
Flash Player Garbage Collection
Flex Component Development
Deep Dive into Flash Player Rendering

6 Responses
  1. January 22, 2011

    Great site. A lot of useful information here. I’m sending it to some friends!

  2. January 24, 2011

    this post is very usefull thx!

  3. February 3, 2011

    i like it Optimizing the Flex Runtime | Brad Rogers.clear now im your rss reader

  4. February 6, 2011

    I’d be inclined to recognize with you here. Which is not something I usually do! I love reading a post that will make people think. Also, thanks for allowing me to comment!

  5. February 15, 2011

    i same it Optimizing the Flex Runtime | Brad Rogers.net very lately im your rss reader

  6. February 17, 2011

    i like it Optimizing the Flex Runtime | Brad Rogers.net now im your rss reader

Comments are closed.