If the number one cause of performance problems is unnecessary measurement
and layout from superfluous container nesting, the number two
cause is creating objects before they are needed. To avoid this problem,
you can use deferred instantiation. Flex uses deferred instantiation to
determine which components to create at application startup. When using
deferred instantiation, you can decide at which stages the user incurs
the costs of component creation. Containers
have a creationPolicy property that you set to specify when
Flex should create the container (at startup, incrementally, when a user
navigates to that container, or based on other user action).
The Flex navigator containers (ViewStack, Accordion, TabNavigator) have built-in deferred instantiation behavior. The default deferred instantiation behavior means that Flex does not create all the child views at startup, but only when a user triggers it by navigating to the container. The following code shows two navigator containers, TabNavigator and ViewStack, in use:
<mx:TabNavigator> <mx:VBox id="tabNavView1"> <mx:LinkBar dataProvider="myViewStack" /> <mx:ViewStack id="myViewStack"> <mx:VBox id="view1" > . . . </mx:VBox> <mx:VBox id="view2" > . . . </mx:VBox> <mx:VBox id="view3" > . . . </mx:VBox> </mx:ViewStack> </mx:VBox> <mx:VBox id="tabNavView2"> . . . </mx:VBox> </mx:TabNavigator>
The TabNavigator container creates tabNavView1 because it is the first view displayed when Flex instantiates the TabNavigator container. Instantiating tabNavView1 will cause the LinkBar and the first view of the ViewStack, view1, to be instantiated. When the user interacts with the LinkBar to select another view in the ViewStack, Flex will create that view. Flex continues in this way, creating the navigator container descendants as it calls them.
The creationPolicy property on container tags control the creation
of child views. The following list explains what each creationPolicy property
does when set on Flex navigator containers:
creationPolicy="auto"—When Flex creates the
navigator containers, it does not immediately create all of their
descendants, only those that are initially visible. The result
of this deferred instantiation is that an MXML application with
a navigator container loads quickly, but users experience a brief
pause the first time they navigate from one view to another. Usability
studies have shown this is a better user experience then having
to wait a noticeable amount of time at application startup to create
the navigator containers' child views. Also, there is always the
possibility that the user may never visit some of the child
views, so creating them at startup is potentially wasteful.
Note that if you set creationPolicy="auto" on a
non-navigator container, you must add extra code to specify when
to create the container's children. This extra
code is built-in in the navigator containers, which is why
you can set creationPolicy="auto" on
a navigator container without doing any extra work.
creationPolicy="all"—When Flex creates the
navigator containers, it creates all of the controls in all their child
views. This setting causes a delay in application startup time, but results
in a quicker response time when navigating from view to view.creationPolicy="none"—Flex does not instantiate
any component within the navigator container or any of the navigator component's
child views until you explicitly call the instantiation methods. You explicitly
instantiate views with the createComponents() method. The
Flex documentation has more information on setting up a custom component
creation plan.creationPolicy="queued"—Flex creates all
containers and then creates the children of the queued containers in
the order in which they appear in the application unless you specify
a creationIndex property. This setting causes components
in your application to become visible in successive fashion, reducing
the amount of time it takes for the user to start viewing the application.
In the following "Progressive
Layout" section I
give an example and more information on this feature. By playing with the creationPolicy properties, you can manually
handle the creation of child views and decide where in your application
architecture you want to incur the cost of creating the child views of
your navigator containers. Usability studies show that a better
user experience is proffered when using the auto setting. A common
mistake that can inadvertently slow your application startup time is to
mistakenly set creationPolicy="all" on
one of your navigator containers. Use creationPolicy="all" only
if you are completely sure that the component creation plan you have in
place is efficient and timely.
In the process of fine-tuning performance, you may reach a point where you have whittled your application's startup time to as fast as possible. However, this does not mean there are no more performance improvements you can make; you could choose to use progressive layout. Progressive layout is a UI concept that involves wiring your application to lay out components in a piece-by-piece fashion so there is a shorter initial delay before components begin appearing on the screen. Progressive layout is similar to the way HTML applications load content in succession in a client.
Progressive layout does not quantifiably reduce application startup time, but it significantly improves the perceived startup time. You implement progressive layout by using the queued creationPolicy in the deferred instantiation architecture of Flex. See the example below, which loads three panels in successive fashion.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" >
<mx:HBox>
<mx:Panel id="panel1" title="Panel 1" width="210" height="240" horizontalAlign="center" verticalAlign="middle" creationPolicy="queued" creationIndex="1">
<mx:DataGrid width="190" height="95">
<mx:dataProvider>
<mx:Array>
<mx:Object Artist="Death Cab for Cutie" />
<mx:Object Artist="The Postal Service" />
</mx:Array>
</mx:dataProvider>
</mx:DataGrid>
<mx:DataGrid width="190" height="95">
<mx:dataProvider>
<mx:Array>
<mx:Object Album="Such Great Heights" />
<mx:Object Album="We Know the Facts" />
</mx:Array>
</mx:dataProvider>
</mx:DataGrid>
</mx:Panel>
<mx:Panel id="panel2" title="Panel 2" width="210" height="240" horizontalAlign="center" verticalAlign="middle" creationPolicy="queued" creationIndex="2">
<mx:List width="190" height="95">
<mx:dataProvider>
<mx:Array>
<mx:String>one</mx:String>
<mx:String>two</mx:String>
<mx:String>three</mx:String>
<mx:String>four</mx:String>
</mx:Array>
</mx:dataProvider>
</mx:List>
<mx:List width="190" height="95">
<mx:dataProvider>
<mx:Array>
<mx:String>red</mx:String>
<mx:String>green</mx:String>
<mx:String>yellow</mx:String>
<mx:String>blue</mx:String>
</mx:Array>
</mx:dataProvider>
</mx:List>
</mx:Panel>
<mx:Panel id="panel3" title="Panel 3" width="210" height="240" horizontalAlign="center" verticalAlign="middle" creationPolicy="queued" creationIndex="3">
<mx:Tree width="190" height="95">
<mx:dataProvider>
<mx:XML>
<node label="File">
<node label="Open"/>
</node>
<node label="Close">
<node label="Help"/>
</node>
</mx:XML>
</mx:dataProvider>
</mx:Tree>
<mx:TextArea width="190" height="95">
<mx:text>The Macromedia Flex presentation server offers a familiar, standards-based programming framework and powerful set of components for creating a rich, responsive presentation tier for enterprise Rich Internet Applications (RIAs).</mx:text>
</mx:TextArea>
</mx:Panel>
</mx:HBox>
</mx:Application>Jason Szeto, a developer on the Flex team, has written an in-depth article on implementing progressive layout in Flex applications, including using progressive layout in data-driven applications:"Building Flex Applications with Progressive Layout."