At work, we've been having some significant performance issues with the Flex
AdvancedDataGrid control, so my boss has
begun a dialog with some of the
AdvancedDataGrid control's developers over at Adobe. As part
of that dialog, my boss asked me to write a brief summary of the problem - which I've done. But it has occurred to me
that the problem description is likely to be very interesting to some people, so I've decided to publish it here too.
And so, here it is...
Here is a brief description of the way we use the
AdvancedDataGrid control, and why I believe it is so slow when used
in this way.
We use the
AdvancedDataGrid to display XML data in a hierarchical data tree. The XML / hierarchical data contains
items of various types such as people, and emails. Initially, the
AdvancedDataGrid shows only a single navigation
tree column, the label field of which simply contains a "summary" of the properties for each item. However, when the
user selects a row, we then switch the
AdvancedDataGrid's columns to a set of detailed columns specific to the
selected row's type. For example, if a person is selected, then we might show "Firstname" and "Surname" columns.
We currently achieve this behaviour by performing two key actions on the
column set switching, and column span switching.
Column Set Switching
To switch the
AdvancedDataGrid's column set, we do the most obvious thing: assign a new array of
objects to the
property. This is very slow - more on this later.
Column Span Switching
Initially, the navigation tree (which shows a text summary of each item) spans all columns. However, when a row is
selected, and thus detailed columns set for that row's type, then we do not want the navigation tree to span all columns
for rows of that type, otherwise the tree will completely overlap the detail columns.So, we use a custom
class that overrides the protected
checkMatch function to dynamically set its own
property according to the assigned data object, and selected row type. This currently works quite well.
The problem is that the
AdvancedDataGrid is extremely slow when switching columns. This seems to be a result of the
AdvancedDataGrid destroying, and then recreating all of it's item renderers any time the column set is changed.
Specifically, the following calls / events occur:
columnssetter function sets a private
columnsChangedflag to true.
- As a result, the
AdvancedDataGrid.commitProperties()[http://livedocs.adobe.com/flex/3/langref/mx/controls/listClasses/AdvancedListBase.html#commitProperties()) function calls the (super)
AdvancedDataGridBaseEx.columnssetter function calls the private
AdvancedDataGridBaseEx.columnRendererChanged()function for each column.
AdvancedDataGridBaseEx.columnRendererChanged()sets the protected (super super)
- This causes the
AdvancedDataGridBaseEx.updateDisplayList()function, when next called, to call a private
- Of course,
AdvancedDataGridBaseEx.purgeItemRenderers()discards all of the
AdvancedDataGrid's item renderers.
- Finally, the various
updateDisplayList()functions in the
AdvancedDataGridclass hierarchy go about recreating all of the item renderers from scratch.
When the application window is small, the above steps can be reasonably quick. However, when the application is maximised, it can easily be showing more than 50 rows, with at least 10 columns - so well over 500 item renderers are being destroyed and then recreated. The Flex Builder Profiler suggests that the construction phase, particularly component measurement, is the most time consuming part.
Showing / Hiding Columns Instead
Since assigning values to the
columns property always results in a full recreation of all
renderers, we've considered avoiding that assignment by merely showing / hiding the desired columns instead. While this
is indeed a bit faster, it is still quite slow (a lot of item renderers still need to be re-measured, etc) and then
exposes several other bugs / limitations in the
For example, as mentioned above, we use a custom
AdvancedDataGridRendererProvider class that changes its
property according to the assigned data object, and selected row type. This works correctly when the column set is
re-assigned, since the recreation of the item renderers causes the
AdvancedDataGrid to evaluate the
property. However, if the recreation is avoided by showing / hiding columns instead, then there is currently no way for
AdvancedDataGrid control to recognise that the navigation column's
columnSpan property has / should change.
This seems to be because the
AdvancedDataGrid only evaluates the
property when rows are being constructed, and not at any other time.
Possible Adobe Fixes
Be conservative when purging item renderers
As mentioned above, when the
AdvancedDataGrid columns are changed, all item renderers are purged. It seems to me,
that at the very least, it would be better if the
AdvancedDataGrid was able to correctly purge only the
no-longer-needed renderers, and simply resize those that remain (assuming that they are of the same renderer class of
course). Perhaps even better, would be some kind of caching of unnecessary item renderers, to make reinstating columns
Fix / extend the showing / hiding columns code
As mentioned above, there are numerous bugs in the
AdvancedDataGrid that are exposed when columns are shown and
hidden - especially if the item renders are not all the same height, in which case the
AdvancedDataGrid gets quite
confused about how high a given row should be. If these bugs get fixed, and the
AdvancedDataGrid extended to allow
cells to change their
columnSpan property, then this may be a better approach from a performance point of view.
Unfortunately, though, given just how slow Flex seems to be a measuring and
laying out a couple of hundred items, I doubt the
AdvancedDataGrid will ever be truly fast at changing columns when
populated with data. Perhaps there needs to be some far more fundamental work done to Flex's layout routines. Indeed,
even laying out a dozen components can be slow under Flex, so its no wonder that 500+ components is so slow.
By the way, we've tested the
AdvancedDataGrid from the pre-release
version of Flex Builder 3.1.0 (2511), but that has not helped to improve these particular issues in any discernible way.
I'll keep you posted on any feedback we get from Adobe... though I'm not expecting any real solutions any time soon :|