Understanding Asynchronous Directory Searching in Adobe AIR
This article has been removed from your 'Articles to Read' list.

Performing the Search
Lets look at the code to search the directory.
private function processDir(dir:DirectoryDataItem):Boolean{
var bReturn:Boolean = true;
try{
var viddir:File = new File(dir.DirectoryPath);
for each(var file:File in viddir.getDirectoryListing()){
if(file.isDirectory){
var di:DirectoryDataItem = new DirectoryDataItem();
di.DirectoryPath = file.nativePath;
di.DirectoryType = dir.DirectoryType;
processing.addItem(di);
} else {
for each(var ext:String in SettingsManager.Instance.GetVideoExtensions()){
if(file.extension == ext){
addFileToLibrary(file, "Video");
}
}
}
}
} catch(er:Error){
bReturn = false;
}
return bReturn;
}
Each directory is passed to this function. This function looks at each entry in the directory. If a sub directory is found it is added to the processing ArrayCollection. If a file is found then it is passed to a function to be added to the library.
As you can see, if this function was called and blocked the application the user could experience long lag times. The way to get this to run Asynchronously is to create a public function that will act as a wrapper and get the search process started. EventListeners will be set up to report the status of the search but the wrapper function will return control to the calling function. This way the user can continue to interact with the GUI and still be updated as files are found.
Lets take a closer look at how to get all this asynchronous event driven stuff to work. I always like to start by breaking my goals down into the components that are going to accomplish each step. We will need the following:
1) Function to recursively search each directory.
2) Mechanism for calling the search function asynchronously.
3) Custom Event object to pass messages from the search function back to the GUI.
4) GUI code that knows how to listen for the custom Event.
For my application I created a class called LibraryManager. It contains all the methods used to do the asynchronous directory search and raise progress events. A complete listing of the code can be found in the file src\radshag\medialibrary\LibraryManager.as inside the source zip file at the top of this tutorial. I will now discuss the key functions and events used for the asynchronous search.
There is one function that is used to start the directory searching process.
1. public function BuildLibrary():void
This function initializes two ArrayCollections. The library ArrayCollection is used to store all the files that are found during the search. The processing ArrayCollection is used to store directories that are to be searched. As subdirectories are found they are also added to the processing ArrayCollection. The code for the BuildLibrary function is presented below:
public function BuildLibrary():void{
library = new ArrayCollection;
processing = new ArrayCollection;
// Get a the collection of media directories to search
var dirs:ArrayCollection = SettingsManager.Instance.GetMediaDirectories();
for each(var dir:DirectoryDataItem in dirs){
// Add directory to collection processing to perform the actual search on each directory
processing.addItem(dir);
}
// each time the ENTER_FRAME event is raised call onEnterFrame to process the next directory
addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
}
The onEnterFrame function is responsible for determining if there are any directories to search. Each time the function is called the ArrayCollection processing is checked to see if it contains any item to search. If it does then the next item is removed from the ArrayCollection and passed to processDir. The processDir function determines what kind of files are being searched for and calls the correct function. If a directory is found it is added to the processing ArrayCollection. If a media file is found then the addFileToLibrary function is called.
The new file is added to the public member library ArrayCollection and a new LibraryProgressEvent called progress is raised so any listening object can handle it. Once the processing array is empty signaling that all directories have been searched, the same LibraryProgressEvent is raised but is named complete so that any listening object can access the library once it is completed
At the top of the LibraryManager class file I defined two events as follows:
/**
* A progress event is dispatched when library item is added.
* @eventType radshag.medialibrary.events.LibraryProgressEvent
*/
[Event(name="progress",type="radshag.medialibrary.events.LibraryProgressEvent")]
/**
* A complete event is dispatched when library processing is complete.
* @eventType radshag.medialibrary.events.LibraryProgressEvent
*/
[Event(name="complete",type="radshag.medialibrary.events.LibraryProgressEvent")]
Each time the search function finds a media file a LibraryProgressEvent named progress is raised. Once all the directories and files have been searched the same event is raised but is called complete to signal that directory searching has completed. A complete listing of the LibraryProgressEvent is listed below:
package radshag.medialibrary.events
{
import flash.events.Event;
import flash.filesystem.File;
public class LibraryProgressEvent extends Event
{
public static var PROGRESS:String = "progress";
public static var COMPLETE:String = "complete";
public var completed:int;
public var total:int;
public var file:String;
public function LibraryProgressEvent(type:String, completed:int, total:int, file:String)
{
super(type);
this.completed = completed;
this.total = total;
this.file = file;
}
override public function clone():Event{
var event:LibraryProgressEvent = new LibraryProgressEvent(type, completed, total, file);
return event;
}
}
}

