Flex Modules
Flex Modules are code functionality compiled to dynamically-loadable SWF files that can be loaded and unloaded by an application at run-time.
Modules let you split your application into several pieces, or modules. The main application, or loader, can dynamically load other modules that it requires, when it needs them. It does not have to load all modules when it starts, nor does it have to load any modules if the user does not interact with them.
Any number of applications can share a module, but a module cannot be run by itself, independently of an application.
Modules API
Flex's Module API defines...
IModuleInfo- a handle for a module, provides information such as url and load stateModule- base class for MXML-based modulesModuleBase- base class for ActionScript-based modulesModuleLoader- loads modules dynamically at run-timeModuleManager- singleton, centrally manages dynamically loaded modulesModuleEvent- dispatched for events in the module lifecycle
Module-related ActionScript classes are defined in the mx.modules package.
(The ModuleEvent class is defined in the mx.events package.)
Creating Modules with MXML and ActionScript
The examples below show how to define Modules using MXML and ActionScript. However, inside the <mx:Module> and SampleModule class definitions there really isn't any code defined. This is because aside from extending one the base Module classes there isn't any other code or contract your modules must implement; they're just like any other component.
MXML-based Modules
Modules are defined in MXML using the <mx:Module> tag.
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"> ... </mx:Module>
ActionScript-based Modules
import mx.modules.ModuleBase; public class SampleModule extends ModuleBase { ... }
Aside from extending one the base Module classes there isn't any other code or contract your modules must implement; they're just like any other component. The key to modules is not how the are created, but how they are loaded.
Loading Modules
Modules are dynamically loaded (and unloaded) at run-time over the network.
Both the ModuleManager and ModuleLoaders can be used to load modules.
When an application no longer needs to use a loaded module, it can unload it to free up memory and resources.
Module Manager (mx.modules.ModuleManager)
The ModuleManager (mx.modules.ModuleManager) class manages dynamically loaded
modules.
The ModuleManager class provides a lower-level API for handling modules than the
ModuleLoader class (below).
The ModuleManager is a singleton and is primarily used via the static getModule()
function.
The getModule() function accepts a URL argument and returns an IModuleInfo
instance.
var moduleInfo:IModuleInfo = ModuleManager.getModule( "SampleModule.swf" ); moduleInfo.addEventListener( ModuleEvent.READY, onModuleReady ); moduleInfo.load();
When a Module is loaded and ready, get an instance using IModuleInfo's
factory create() method.
protected function onModuleReady( moduleEvent:ModuleEvent ):void { var moduleInfo:IModuleInfo = moduleEvent.module; var sample:SampleModule = moduleInfo.factory.create() as SampleModule; }
Module lifecycle and status updates are delivered via events to listeners registered
with the ModuleManager.
Commonly used ModuleManager events:
- loading (FlexEvent.LOADING) - dispatched when the ModuleLoader starts to load a URL
- progress (ModuleEvent.PROGRESS) - dispatched at regular intervals as the module loads
- ready (ModuleEvent.READY) - dispatched when the module is finished loading
- error (ModuleEvent.ERROR) - dispatched when the module throws an error
- unload (ModuleEvent.UNLOAD) - dispatched when the module data is unloaded
- setup (ModuleEvent.SETUP) - dispatched when information about the module is available but not yet ready
- urlChanged (FlexEvent.URL_CHANGED) - dispatched when the ModuleLoader is given a new URL
Module Loader (mx.modules.ModuleLoader)
A ModuleLoader (mx.modules.ModuleLoader) class instance is used for loading a
single Module.
A ModuleLoader ensures that only a single copy of a module SWF file is transferred over
the network by using the ModuleManager.
Commonly used ModuleLoader properties:
- url:String - the url location of the module
Commonly used ModuleLoader methods:
- loadModule():void - loads the module
- url:String (optional) - value to set and use for the modules url
- bytes:ByteArray (optional) - a byte array with the contents of a compiled SWF module
- unloadModule():void - unloads the module
Commonly used ModuleLoader events:
- loading (
FlexEvent.LOADING) - dispatched when the ModuleLoader starts to load a URL - progress (
ModuleEvent.PROGRESS) - dispatched at regular intervals as the module loads - ready (
ModuleEvent.READY) - dispatched when the module is finished loading - error (
ModuleEvent.ERROR) - dispatched when the module throws an error - unload (
ModuleEvent.UNLOAD) - dispatched when the module data is unloaded - setup (
ModuleEvent.SETUP) - dispatched when information about the module is available but not yet ready - urlChanged (
FlexEvent.URL_CHANGED) - dispatched when the ModuleLoader is given a new URL
ModuleLoader ActionScript Example
Use the ModuleLoader class directly to load a Module using ActionScript.
import mx.events.ModuleEvent; import mx.modules.ModuleLoader; public function loadSampleModule():void { // the url to the module can be relative or absolute var moduleUrl:String = "SampleModule.swf"; var loader:ModuleLoader = new ModuleLoader( moduleUrl ); // register event listeners loader.addEventListener( ModuleEvent.PROGRESS, handleModuleProgress ); loader.addEventListener( ModuleEvent.READY, handleModuleReady ); loader.addEventListener( ModuleEvent.ERROR, handleModuleError ); // start the module loading loader.load(); }
Below you will find examples of event handler functions for ModuleEvents (in the Module Events example section).
ModuleLoader MXML Example
Use the <mx:ModuleLoader> tag to load a Module using MXML.
<!-- Load module with event handlers for progres, ready, and error. --> <mx:ModuleLoader url="SampleModule.swf" progress="handleModuleProgress(event);" ready="handleModuleReady(event);" error="handleModuleEvent(event);" />
Below you will find examples of event handler functions for ModuleEvents
(in the Module Events example section).
Module Events
Module Events (mx.events.ModuleEvent) are fired during a Module's lifecycle by
ModuleLoader and ModuleManager.
ModuleEvent types defined as static properties:
- PROGRESS ("progress") - dispatched when the module is in the process of downloading
- READY ("ready") - dispatched when the module has finished downloading
- ERROR ("error") - dispatched when there is an error downloading the module
- UNLOAD ("unload") - dispatched when the module is unloaded
- SETUP ("setup") - dispatched when enough of a module has been downloaded that you can get information about the module
ModuleEvent properties (inherited from ProgressEvent):
- module:IModuleInfo - information about the module
- bytesLoaded:Number - number of items or bytes loaded
- bytesTotal:Number - total number of items or bytes that will be loaded if the loading process succeeds
Example Module Event Handlers
The following code shows an example of what a Module event handler could look like for the above examples.
// handle ModuleEvent.PROGRESS protected function handleModuleProgress( moduleEvent:ModuleEvent ):void { // update a ProgressBar control progressBar.setProgress( moduleEvent.bytesLoaded, moduleEvent.bytesTotal ); } // handle ModuleEvent.READY protected function handleModuleReady( moduleEvent:ModuleEvent ):void { // let the user know the module was loaded progressLabel.setText( "Module completed loading: " + moduleEvent.bytesTotal + " bytes" ); } // handle ModuleEvent.ERROR protected function handleModuleError( moduleEvent:ModuleEvent ):void { // throw an error throw new Error( "Module error loading: " + moduleEvent.module.url ); }
Passing query string data to Modules
Query string parameters (e.g. ?param=value) can be appended to the URL used to
load a Module.
<!-- Load module with query parameters on the URL. --> <mx:ModuleLoader url="SampleModule.swf?firstName=Joe&lastName=Public" />
The query string parameters can then be accessed in the Module using its
loaderInfo property.
(Unfortunately the parameters must be parsed manually in ActionScript.)
The below example shows how to access and parse the query string parameters passed in the URL used to load a module.
public function getQueryParams():Object { var url:String = this.loaderInfo.url.toString(); // remove everything before the question mark, including the question mark var regexQuery:RegExp = /.*\?/; var queryString:String = url.replace( regexQuery, "" ); // create an array of name=value pairs var paramArray:Array = queryString.split( "&" ); // put the names value into an object var paramObject:Object; var param:String; var pair:Array; for each( param in paramArray ) { pair = param.split( "=" ); // name = value paramObject[ pair[0] ] = pair[1]; } return paramObject; }
Module and Parent Application Communication
Modules can access properties and methods of the parent application by using
the parentApplication property.
Loader applications access properties and methods of Modules by loading them and creating an instance (which has already been explained above).
Module to Module Communication
Modules can also communicate with other Modules loaded by the same application.
You can access properties and methods of other modules through the parent application
using a ModuleLoader's child property.
This property points to an instance of the module's class, which lets you call methods
and access properties.
Consider the following example where a parent application loads two modules,
Module1 and Module2.
<!-- Loader (parent) application... --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:ModuleLoader url="Module1.swf" id="module1"/> <mx:ModuleLoader url="Module2.swf" id="module2"/> </mx:Application>
Inside of module1 you could call a method or access a property as below.
// inside of Module1 parentApplication.module2.child.someProperty; parentApplication.module2.child.someMethod();
Benefits of Modules
Modular applications provide the following benefits:
- Applications can have a smaller initial download size and shorter load times
- Application modules can be loaded in pieces as they are used
- Applications can be better encapsulated and pieces worked on independently
Modules vs. Runtime Shared Libraries (RSL)
Both Runtime Shared Libraries (RSL) and Modules are code separation and reuse mechanisms. They share some similarities and have some differences.
Compilation:
- Modules are compiled into SWF (.swf) files
- Libraries are compiled into SWC (.swc) files
Usage:
- Modules are loaded (and can be unloaded) at run-time
- Libraries are used at compile time and compiled into an application
Application Size:
- Modules do not contribute to the initial size or load time of an application
- Libraries used by an application increase its compilation size
Loading Modules accross Domains
To load a Module from one server into an application served from a different server, you must first establish a trust between the module and the application that loads it.
Loading modules accross domains requires use of a Cross Domain Policy file (crossdomain.xml).
Step 1: Loader Application Initialization
In the preinitialize event handler of the loading application call the
allowDomain() method, specifying the target domain from which to load a module.
Also load the cross-domain file of the remote server using
loadPolicyFile() and by issuing a URLRequest.
// (Loader) Application initialization public function initApp():void { Security.allowDomain( "remoteservername" ); Security.loadPolicyFile( "http://remoteservername/crossdomain.xml" ); var request:URLRequest = new URLRequest( "http://remoteservername/crossdomain.xml" ); var loader:URLLoader = new URLLoader(); loader.load( request ); }
Step 2: Server Cross Domain Policy
In the cross-domain file of the remote server where your module is, add an entry that specifies the server on which the loading application is running.
<!-- crossdomain.xml file located at the root of the server --> <cross-domain-policy> <allow-access-from domain="loaderservername" to-ports="*"/> </cross-domain-policy>
Step 3: Module Initialization
In the loaded module, call the allowDomain() method so that it can communicate with
the loader.
// (Remote) Module initialization public function initModule():void { Security.allowDomain( "loaderservername" ); }
Examples
Monitoring Module Loading with a Progress Bar
TODO...
...

