Archive for January, 2007

New Flex Tools on Adobe Labs

Adobe Labs have just announced two tools Flex 2:

http://labs.adobe.com/wiki/index.php/Flex_Ant_Tasks
Flex Ant Tasks provides a convenient way to build your Flex projects using an industry-standard build management tool.

http://labs.adobe.com/wiki/index.php/Flex_Compiler_Shell
Flex Compiler Shell provides a shell environment that you use to compile Flex applications, modules, and component libraries.

Customer Advisory Board – Members Wanted

Adobe is looking for experienced PHP, Java, ColdFusion, and Ajax developers to participate in an advisory panel on the future of Adobe Flex. If you would like to help shape the future of rich internet applications, fill out the following survey (no prior Flex experience required):

https://prerelease.adobe.com/callout/default.html?callid=90D54BEDFD134F6D886F50C5DF830AB2

Selected respondents for the private panel will have the opportunity to provide feedback on future versions of Adobe Flex and test early releases of Adobe software. In appreciation, all active participants will be eligible to receive a complimentary license of an Adobe desktop product.

We’d like your opinion

Visit the flex.org website and take the Flex Charting survey. You’ll also find links to entries from the Flex Team.

Building Modular Applications

If you haven’t been to Roger Gonzalez’s blog about Modules, then zip over there and get the details and thoughts behind this feature of Flex 2. I’m not going to go too much into the why’s but want to show you a simple Flex application that uses Modules. You can let your imagination take it from there.

Sample Code

You can download a zip file with this example here: download here

Modules

Modules are one solution to building a large Flex application by allowing you to partition your user interface into useful, descrete bits. For example (and this is from the Flex 2 documentation), an insurance company might have hundreds of forms – specific to each region, specific to each type of claim, specific to each application, etc. Creating a Flex application with all of these forms would result in a huge SWF with several problems:

  • The larger the ‘application’ the more complex the development process;
  • The larger the ‘application’ the more complex the testing process.
  • The larger the ‘application’ the more complex the deployment process;
  • The larger the SWF the longer it takes to download;

My sample application is based on one in the Flex 2 documentation, but I’ve modified it a bit to address a couple of common questions. The sample shows a main, or shell application and three modules which share common data.

One important design element is the use of an interface which is essentially a contract between the implementor of the interface and the users of that same interface. This example will show you what I mean. The interface portion of modules is not necessary but it makes maintenence and future development go a lot smoother. For example, if you have one team working on the report screens and another team working on the chart screens, if they first agree on the interfaces, the implementations can take as many twists and turns as necessary without affecting the outcome of the project. Interfaces also play another role with modules which I reveal later.

Modules are MXML (or ActionScript) files that have <mx:Module> as their root tag instead of <mx:Application>. Think of the <mx:Module> tag as an Application, but without the ability to run it.

The sample application has a shell file and two modules along with an interface. Open the main application file and you will see:

<mx:Panel x="10" y="41" width="169" height="500" layout="absolute" title="Modules">
      <mx:Text x="10" y="24" text="Check a module to load it; uncheck to unload it" width="129"/>
      <mx:RadioButton x="10" y="97" label="None" selected="true"
                          click="removeModule()"/>
      <mx:RadioButton x="10" y="123" label="Chart"
                         click="removeModule();loadModule(‘ChartModule.swf’)"/>
      <mx:RadioButton x="10" y="175" label="Table"
                        click="removeModule();loadModule(‘GridModule.swf’)"/>
</mx:Panel>

<mx:Panel x="187" y="41" width="500" height="500" layout="absolute" title="Module: {moduleName}">
       <mx:ModuleLoader id="currentModule" ready="readyModule(event)"
                       width="100%" height="100%" />

</mx:Panel>

The first Panel contains RadioButtons to get the modules to load and unload for the demonstration. The second Panel is where the modules are loaded using the <mx:ModuleLoader> tag. Notice that the ModuleLoader, currentModule, has an event handler for the ready event. The ready event (or ModuleEvent.READY) is dispatched by the ModuleLoader when enough of the module SWF has been downloaded to begin using it.

This is the readyModule function, in a <mx:Script> block:

private function readyModule( event:ModuleEvent ) : void
{
       var ml:ModuleLoader = event.target as ModuleLoader;

      var ichild:IExpenseReport = ml.child as IExpenseReport;
      if( ichild != null ) {
               ichild.expenseReport = expenses;
      }
}

Notice how the child property of the ModuleLoader is cast to the class IExpenseReport. IExpenseReport is an interface which all of the modules implement. As long as every module implements this interface, it can fit easily into the application. In other words, imagine that you need to make another form or report. Instead of changing the main application and adding IF statements for the new module, you implement the IExpenseReport interface in the new module and it will work perfectly with the application.

The IExpenseReport interface is:

public interface IExpenseReport
{
      function set expenseReport( ac:ArrayCollection ) : void;
}

Each module implements this interface, defining the expenseReport set function as it sees fit. This is the root tag for the ChartModule and the implementation of the IExpenseReport interface:

<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" implements="IExpenseReport"
            layout="vertical"
            percentWidth="100" percentHeight="100" >

     <mx:Script><![CDATA[
           import mx.collections.ArrayCollection;
           [Bindable]
public var expenses:ArrayCollection;

           public function set expenseReport( ac:ArrayCollection ) : void
           {
                 expenses = ac;
            }

     ]]></mx:Script>

</mx:Module>

Going back to the main application shell, the RadioButton click event causes any currently loaded module to unload and then loads a new module. Here is the RadioButton tag for the ChartModule:

<mx:RadioButton x="10" y="123" label="Chart" click="readyModule(‘ChartModule.swf’)"/>

The click event invokes the readyModule which is listed above.

Compiling and Running the Application

If you are using Flex Builder 2, be sure to modify the project’s properties to include the modules as applications. This way Flex Builder 2 will compile them into SWFs and place them into the bin directory.

Flex Builder Note: To build a project with Modules, use the project’s Properties and add the module files as "Applications". This will get them compiled into SWFs.

Once the SWFs have been built you can run the main shell application and click the RadioButtons to switch between the modules.

Flex Builder Note: Flex Builder does not maintain any dependency information about your modules and the shell application. Whenever you make a change to a module you may need to force a recompile on the shell or other modules with dependencies.

Optimizing the SWFs

If you take a look at the size of the SWFs for the main application and modules you will see that they are similar in size. Meaning, the module SWFs have many of the same component definitions in them as the main application SWF.

The Flash Player does not keep duplicate copies of symbols. For instance, if the main Application has a Button component and a module also has a Button component, the Flash Player will not load the Button from the module since it already has that definition from the main application.

Compile the main application with -link-report=report.xml which will create a file containing information about all of the symbols that it is being linked with. Then use that report when compiling the modules. For example:

mxmlc -load-externs=report.xml ChartModule.mxml

When ChartModule is compiled, all of the symbols listed in the link report, report.xml, are left out of its SWF. When I compiledthe ChartModule.swf without doing this, it came to 202K. When I used the report.xml, the SWF become only 68K in size. This greatly reduces the download time for modules.

In the beginning of this entry I mentioned another use for interfaces when it comes to modules. Suppose you do not use an interface but instead reference your modules’ classes from your shell application. When you run the link-report, your modules’ classes will appear in the report. When you compile your modules using that link report your module will not be included in its own SWF! At first that won’t be a problem, although the main shell application will be large since it holds the definitions of your modules. As important however, is what happens when you change your modules. If you do not recompile your main application, your main application’s SWF will have the old definition of your modules – not the changes you made.

mxmlc -link-report=report.xml Main.mxml
mxmlc -load-externs=report.xml ChartModule.mxml
// etc.

If you decide to use this technique for reducing your modules’ sizes, use interfaces to make sure the end-user always has the latest version of your modules.

Flex Builder Note: Flex Builder does not have a way to do this for you within a single project. If you believe you will be building a project using modules, consider putting common classes and interfaces (including event classes) into a SWC (Flex Library Project) and separating the modules into their own projects.

Or, you can build everything as a single Flex project and do the optimzation outside of Flex Builder as a pre-production or pre-test deployment step.

Summary

  • Divide applications which have parts that not everyone will use into modules. This way the initial main application is smaller than it would normally have been and most users will only use a portion of the entire application.
  • Use interfaces to allow the shell or including modules to communicate with the modules they load. This makes it easier to maintain.
  • Compile the main application using the -link-report compiler switch to generate a list of symbols it is using.
  • Compile the modules with -load-externs and the link report from the main application which makes them smaller.

Happy New Year: Flex 2.0.1 is Here!

We’ve pushed the bits for Flex 2.0.1 to the Adobe site and you can – and should – grab it and install it.

We’d like everyone to upgrade to Flex 2.0.1. There are new features and fixes in this release.

You can read more about what’s in Flex 2.0.1 in Matt Chotin’s article on DevNet.

This upgrade is free. If you have Flex Builder 2, this will simply upgrade your install – it is not a new installation. Your license, projects, etc. are preserved.