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.
public class MyGraphics extends ModuleBase implements TimeLinerGraphicsModule{[Embed(source="/art/toolbars/add.png")]protected var _addIcon:Class;public function get addIcon() : Class { return _addIcon; }
…}
NEVER import or otherwise use this class into your application. The goal is to keep it completely separate.
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.