AdvancedDataGrid column switching performance

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 AdvancedDataGrid's (selection) change event: column set switching, and column span switching.

1. Column Set Switching

To switch the AdvancedDataGrid's column set, we do the most obvious thing: assign a new array of AdvancedDataGridColumn objects to the AdvancedDataGrid.columns property. This is very slow - more on this later.

2. 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 AdvancedDataGridRendererProvider class that overrides the protected checkMatch function to dynamically set its own columnSpan property according to the assigned data object, and selected row type. This currently works quite well.

The Problem:

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 its item renderers any time the column set is changed. Specifically, the following calls / events occur:

  1. The AdvancedDataGrid's columns setter function sets a private columnsChanged flag to true.
  2. As a result, the AdvancedDataGrid.commitProperties() function calls the (super) AdvancedDataGridBaseEx's columns setter function.
  3. The AdvancedDataGridBaseEx columns setter function calls the private AdvancedDataGridBaseEx.columnRendererChanged() function for each column.
  4. AdvancedDataGridBaseEx.columnRendererChanged() sets the protected (super super) AdvancedListBase.rendererChanged flag to true.
  5. This causes the AdvancedDataGridBaseEx.updateDisplayList() function, when next called, to call a private AdvancedDataGridBaseEx.purgeItemRenderers() function.
  6. Of course, AdvancedDataGridBaseEx.purgeItemRenderers() discards all of the AdvancedDataGrid's item renderers.
  7. Finally, the various updateDisplayList() functions in the AdvancedDataGrid class 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 AdvancedDataGird's 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 AdvancedDataGrid.

For example, as mentioned above, we use a custom AdvancedDataGridRendererProvider class that changes its columnSpan 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 AdvancedDataGridRendererProvider's columnSpan property. However, if the recreation is avoided by showing / hiding columns instead, then there is currently no way for the AdvancedDataGrid control to recognise that the navigation column's columnSpan property has / should change. This seems to be because the AdvancedDataGrid only evaluates the AdvancedDataGridRendererProvider's columnSpan property when rows are being constructed, and not at any other time.

Possible Adobe Fixes

1. 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 quicker too.

2. 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 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 :|

comments powered by Disqus