The spark List component is designed to render large datasets into a small viewport. However, when you need to display hundreds of itemrenderers at the same time, the performance can drop drastically.

Here’s a basic List component that displays >300 small itemRenderers in the viewport. The dataProvider has 10,000 items. Try dragging the scrollbar thumb.
(See the optimised version at the bottom of this page).

(right click to view source.)

<s:List width="100%" height="100%" top="10"
            dataProvider="{colours}" >
        <s:layout>
            <s:TileLayout horizontalGap="1" verticalGap="1" />
        </s:layout>
        <s:itemRenderer>
            <fx:Component>
                <s:ItemRenderer width="20" height="6" >
                    <s:Rect width="100%" height="100%">
                        <s:fill>
                            <s:SolidColor color="{data}" />
                        </s:fill>
                    </s:Rect>
                </s:ItemRenderer>
            </fx:Component>
        </s:itemRenderer>
    </s:List>
<s:List width="100%" height="100%" top="10"
            dataProvider="{colours}" >
        <s:layout>
            <s:TileLayout horizontalGap="1" verticalGap="1" />
        </s:layout>
        <s:itemRenderer>
            <fx:Component>
                <s:ItemRenderer width="20" height="6" >
                    <s:Rect width="100%" height="100%">
                        <s:fill>
                            <s:SolidColor color="{data}" />
                        </s:fill>
                    </s:Rect>
                </s:ItemRenderer>
            </fx:Component>
        </s:itemRenderer>
    </s:List>

The Spark List component is designed to use a separate itemrenderer for each item in the viewport, then – if possible – re-use them when you are scrolling up or down. So, in the example above, instead of creating 10,000 itemrenderers, the spark list component only creates ~300:
itemrenderer Flex Performance Tuning   superfast list component

This approach works perfectly if you only have a few itemrenderers on stage, ie. the itemrenderers are big and/or the viewport is small.

If you have a big viewport with small itemrenderers, even if the itemRenderers are lightweight, you will end up with too many displayobjects on the stage and the invalidation phase will be painfully slow.

A Different Approach

When you want to display hundreds/thousands of items on screen simultaneously, consider using a canvas(eg. a BitmapData object), where you can “paint” your items:

    <s:BitmapImage id="bmp" width="100%" height="100%"
                   source="{itemRenderer.canvas}"  >
    </s:BitmapImage>
 
    <s:VScrollBar id="scr" skinClass="spark.skins.spark.VScrollBarSkin"
                  right="0" height="100%" >
        <s:change>
            <![CDATA[
                invalidateDisplayList();
            ]]>
        </s:change>
    </s:VScrollBar>
    <s:BitmapImage id="bmp" width="100%" height="100%"
                   source="{itemRenderer.canvas}"  >
    </s:BitmapImage>

    <s:VScrollBar id="scr" skinClass="spark.skins.spark.VScrollBarSkin"
                  right="0" height="100%" >
        <s:change>
            <![CDATA[
                invalidateDisplayList();
            ]]>
        </s:change>
    </s:VScrollBar>

itemrenderer2 Flex Performance Tuning   superfast list component

When you scroll around, you can use

bitmapdata.scroll(0,scrollAmount)
bitmapdata.scroll(0,scrollAmount)

, so you only have to render the area you scrolled into:

itemrenderer3 Flex Performance Tuning   superfast list component

Optimised example:

The dataprovider is the same as the one in the previous example: 10,000 items, ~300 in the viewport. Try dragging the scrollbar thumb:

(right click to view source)

    <local:BitmapList width="100%" height="100%" top="10"
                      dataProvider="{colours}" >
        <local:itemRenderer>
            <local:BitmapListItemRenderer width="20" height="6" />
        </local:itemRenderer>
    </local:BitmapList>
    <local:BitmapList width="100%" height="100%" top="10"
                      dataProvider="{colours}" >
        <local:itemRenderer>
            <local:BitmapListItemRenderer width="20" height="6" />
        </local:itemRenderer>
    </local:BitmapList>

Here ALL items in the viewport are re-rendered on Change event. This can be further optimised by introducing bitmapdata.scroll and only rendering the area we are scrolling into.

Note: This example is just a quick mockup to demonstrate the performance improvement you can gain by replacing hundreds of itemRenderers by a single bitmap. Focus management and layout management are not implemented.

Tagged with:
 

3 Responses to Flex Performance Tuning – superfast list component

  1. Joe says:

    Does the optimized item renderer handle states?

  2. zoltanb says:

    Hi Joe,

    The example above only has a single state, but it’s easy to add multiple states and focus management.
    A simple focus management can be achieved by adding 1 itemrenderer onto the display list that overlays the hovered/selected item.
    If you want to enable multiple selection, it’s gets a bit more complicated.

    This List approach is for edge cases, where the number of on-screen itemrenderers are too large for the framework to handle, especially on resource constrained devices.

  3. Nice! – RT @seantheflexguy: RT @galinos: Flex Performance Tuning – superfast list component http://t.co/gzzInX5y

Leave a Reply

Your email address will not be published. Required fields are marked *

*


− 5 = two

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code lang=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" extra="">