For the past month I've been plagued with up to three minute compile times on Flex Builder 3 Beta 2. I've also been plagued with long several minute waits of "Refresing bin/".
Last week I solved the issue for one of my projects and prevented it from happening to another.
Apparently embedding graphics causes a performance hit in compiling, refreshing directories, and even just before launching. So if you have a hundred or so of these:
<mx:Button icon="@Embed(...)" />
You'll be in a world of pain. The easiest solution is to move those embed calls into your style sheet and then compile your style sheet as a module.
Here's how to make a style sheet module:
1) Create a new MXML module (file->new->flex->MXML module)
2) Add your stylesheet reference to that.
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" width="0" height="0"
creationComplete="trace('iconsloaded')">
<mx:Style source="style.css" />
</mx:Module>
3) Next, remove the reference to your style sheet from your main application.
4) Now, in your main MXML or AS file add some code to load your module.
protected var styleLoader:ModuleLoader;
protected function init() : void
{
styleLoader = new ModuleLoader();
styleLoader.addEventListener(ModuleEvent.READY, onModuleLoad );
styleLoader.addEventListener(ModuleEvent.ERROR, onModuleError );
styleLoader.url = "IconsModule.swf";
styleLoader.loadModule();
}
protected function onModuleLoad( e:ModuleEvent ) : void
{
maximize();
var mainApp:MainApplication = new MainApplication();
mainApp.percentHeight = 100;
mainApp.percentWidth = 100;
addChild(mainApp);
}
protected function onModuleError(e : ModuleEvent ) : void
{
Alert.show("Could not load module IconsModule.swf","Error",Alert.OK );
}
You can see there that I intialize my main application component after the module has loaded. I didn't have to do this in a Flex app, but in my AIR app that component wouldn't get all of the new styles if created before the module was loaded.
Option 2
Sometimes, it wasn't practical for me to put the embedded graphic in a stylesheet. In those cases I:
1) Made an interface listing all the embedded graphics
public interface MyGraphicsModule
{
// Bindable tags are there purely to suppress warnings,
// these properties never change after startup.
[Bindable(event="moduleChanged")] function get addIcon() : Class;
...
}
2) Make a class that implements that interface and extends ModuleBase, also embed the graphics in there.
NEVER import or otherwise use this class into your application. The goal is to keep it completely separate.
public class MyGraphics extends ModuleBase implements TimeLinerGraphicsModule
{
[Embed(source="/art/toolbars/add.png")]
protected var _addIcon:Class;
public function get addIcon() : Class { return _addIcon; }
...
}
3) Create a module manager class
public class MyModules
{
[Bindable] public static var graphics:MyGraphicsModule;
}
4) Set MyGraphics to be a module that gets built in your Project->Properties->Flex Modules settings.
5) Load your module somewhere at startup
public function loadModules() : void
{
graphicsModuleLoader = new ModuleLoader();
graphicsModuleLoader.addEventListener(ModuleEvent.READY, onModuleLoaded );
graphicsModuleLoader.addEventListener(ModuleEvent.ERROR, onModuleLoadFailure );
graphicsModuleLoader.url = "MyGraphics.swf";
graphicsModuleLoader.loadModule();
}
protected function onModuleLoaded( event:ModuleEvent ) : void
{
if( event.target == graphicsModuleLoader )
{
var o:Object = event.module.factory.create();
MyModules.graphics = event.module.factory.create() as MyGraphicsModule;
}
}
6) Find the spot in your code that used that icon and replace it
So this:
[Embed(source="/art/icons/addIcon.png")]
public var addIcon:Class;
Would become this:
public var addIcon:Class = MyModules.graphics.addIcon;
This all seems like a pretty tedius job to do, but I ended up writing a perl script to scour the source tree, find all the references, and replace them for me. Unfortunately I did that script as part of my day-job and can't share it with everyone right now. I'll ask for permission on Monday.
The end result was we went from a 3.5 minute wait from saving a code change to executing the application to a 20 second wait. Not too shabby considering the size of the codebase we have.