Archive for category Flex
“Fixing” the FileSystemTree
Posted by Chris Deely in AIR, Flex on July 23, 2009
I recently ran into some painfully slow performance issues using the FileSystemTree to display file system contents in an AIR app. It seemed that when accessing directories containing a large number of files, the app would simply hang for ages, never populating the tree.
This occurred most readily when accessing network drives. I chased the issue down a number of avenues, including looking at “funky” file types and network speed. Nothing pointed me in the right direction.
Finally, I spent some time placing breakpoints directly into the FileSystemTree class and dug into the guts to find the answer. As I stepped through the code, I found that the file records for the large directory in question were returned from the OS almost instantaneously. This was not what I expected to find, but it was great news, as it meant the processing delay was somewhere inside the Flex SDK or my own code.
Sure enough, there is some code in the FileSystemTree class that significantly slows down the processing of large directories. After loading the raw directory listing from the AIR framework, the child items are processed through the following function:
{
var childCollection:ArrayCollection = new ArrayCollection(childItems);
childCollection.filterFunction =
helper.directoryEnumeration.fileFilterFunction;
childCollection.sort = new Sort();
childCollection.sort.compareFunction =
helper.directoryEnumeration.fileCompareFunction;
childCollection.refresh();
FileSystemTreeDataDescriptor(dataDescriptor).setChildren(
subdirectory, childCollection);
expandItem(subdirectory, true, true);
helper.itemsChanged();
}
The problem here is that the file records returned from the OS are now filtered and sorted before populating the Tree. This is fine for relatively small sets of data, but when dealing with large directories (1600+ files in my case) it grinds to a halt.
The only way I have found to improve the performance of this component is to prevent the filtering and sorting from taking place for large directories. I extended the FileSystemTree (source attached) and overrode the insertChildItems function.
The full class is below:
{
import flash.filesystem.File;
import mx.collections.ArrayCollection;
import mx.collections.Sort;
import mx.controls.FileSystemTree;
import mx.controls.fileSystemClasses.FileSystemTreeDataDescriptor;
import mx.core.mx_internal;
import mx.utils.DirectoryEnumerationMode;
use namespace mx_internal;
/**
* This class overrides the AIR FileSystemTree class' insertChildItems to prevent sorting of directory contents when
* there are a great number of children in the folder. This is far from perfect, as the children may be listed randomly,
* however it is better than the default behavior where the app chokes.
**/
public class FastFileSystemTree extends FileSystemTree
{
/** Adjust this number to set an acceptable threshold for sorted/unsorted children **/
public var largeDirectoryThreshold:Number = 500;
public function FastFileSystemTree()
{
super();
}
override mx_internal function insertChildItems(subdirectory:File, childItems:Array):void
{
var childCollection:ArrayCollection = new ArrayCollection(childItems);
/* This is the only change to the function. If this directory contains a large number of children,
just append them as they are listed from the OS, rather than filtering or sorting them. */
if( childCollection.length < largeDirectoryThreshold )
{
childCollection.sort = new Sort();
childCollection.filterFunction = helper.directoryEnumeration.fileFilterFunction;
childCollection.sort.compareFunction = helper.directoryEnumeration.fileCompareFunction;
childCollection.refresh();
}
FileSystemTreeDataDescriptor(dataDescriptor).setChildren(
subdirectory, childCollection);
expandItem(subdirectory, true, true);
helper.itemsChanged();
}
}
}
This is definitely not a great solution, as the contents of large directories may not appear in exactly the right order. I’ve had mixed results.
The real issue is that this type of operation on large quantities of file references should really be executed within the AIR framework itself, and not by the AS3 components running on top of it.
I am very open to suggestions on how to approach a better solution, but for now this at least allows the user to access their files; albeit in possibly the wrong order.