gembin

OSGi, Eclipse Equinox, ECF, Virgo, Gemini, Apache Felix, Karaf, Aires, Camel, Eclipse RCP

HBase, Hadoop, ZooKeeper, Cassandra

Flex4, AS3, Swiz framework, GraniteDS, BlazeDS etc.

There is nothing that software can't fix. Unfortunately, there is also nothing that software can't completely fuck up. That gap is called talent.

About Me

 

Flex modules

This section describes modules and how they are used by modular applications.

Subtopics

About modules
Benefits of modules
Module API details
Creating modular applications

About modules

Modules are SWF files that can be loaded and unloaded by an application. They cannot be run independently of an application, but any number of applications can share the modules.

Modules let you split your application into several pieces, or modules. The main application, or shell, 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. When the application no longer needs a module, it can unload the module to free up memory and resources.

Modular applications have the following benefits:

  • Smaller initial download size of the SWF file.
  • Shorter load time due to smaller SWF file size.
  • Better encapsulation of related aspects of an application. For example, a "reporting" feature can be separated into a module that you can then work on independently.

Benefits of modules

Modules are similar to Runtime Shared Libraries (RSLs) in that they separate code from an application into separately loaded SWF files. Modules are much more flexible than RSLs because modules can be loaded and unloaded at run time and compiled without the application.

Two common scenarios in which using modules is beneficial are a large application with different user paths and a portal application.

An example of the first common scenario is an enormous insurance application that includes thousands of screens, for life insurance, car insurance, health insurance, dental insurance, travel insurance, and veterinary pet insurance.

Using a traditional approach to rich Internet application (RIA) design, you might build a monolithic application with a hierarchical tree of MXML classes. Memory use and start-up time for the application would be significant, and the SWF file size would grow with each new set of functionality.

When using this application, however, any user accesses only a subset of the screens. By refactoring the screens into small groups of modules that are loaded on demand, you can improve the perceived performance of the main application and reduce the memory use. Also, when the application is separated into modules, developers' productivity may increase due to better encapsulation of design. When rebuilding the application, the developers also have to recompile only the single module instead of the entire application.

An example of the second common scenario is a system with a main portal application, written in ActionScript 3, that provides services for numerous portlets. Portlets are configured based on data that is downloaded on a per-user basis. Using the traditional approach, you might build an application that compiles in all known portlets. This is inefficient, both for deployment and development.

By using modules, you can establish an interface that contains portal services, and a generic portlet interface. You can use XML data to determine which modules to load for a given session. When the module is loaded, you obtain a handle to a class factory inside the module, and from that you create an instance of a class that implements the portlet interface. In this scenario, full recompilation is necessary only if the interfaces change.

Module API details

Modules implement a class factory with a standard interface. The product of that class factory implements an interface known to the shell, or the shell implements an interface known to the modules.

By using shared interface definitions, these shared interfaces reduce hard dependencies between the shell and the module. This provides type-safe communication and enforces an abstraction layer without adding significantly to the SWF file size.

The following image shows the relationship between the shell and the module's interfaces:

 


Relationship between shell application and the module's interfaces.

Creating modular applications

To create a modular application, you create separate classes for each module, plus an application that loads the modules.

To create a modular application:

  1. Create any number of modules. An MXML-based module file's root tag is <mx:Module>. ActionScript-based modules extend the ModuleBase class.
  2. Compile each module as if it were an application. You can do this by using the mxmlc command-line compiler or the compiler built into Adobe Flex Builder.
  3. Create an Application class. This is typically an MXML file whose root tag is <mx:Application>, but it can also be an ActionScript-only application.
  4. In the Application file, use an <mx:ModuleLoader> tag to load each of the modules. You can also do this by using the load() method of the mx.modules.ModuleLoader class. For classes that extend ModuleBase, you should use the methods of the ModuleManager class to load them.

The following sections describes these steps in detail.


Creating modules

Modules are classes just like application files. To create a module in ActionScript, you create a file that extends the mx.modules.ModuleBase class. To create a module in MXML, you extend the mx.modules.Module class by creating a file whose root tag is <mx:Module>. In that tag, ensure that you add any namespaces that are used in that module. You should also include a type declaration tag at the beginning of the file.

The following example is a module that includes a Chart control:

<?xml version="1.0"?>
<!-- modules/ColumnChartModule.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" >
<mx:Script><![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var expenses:ArrayCollection = new ArrayCollection([
{Month:"Jan", Profit:2000, Expenses:1500},
{Month:"Feb", Profit:1000, Expenses:200},
{Month:"Mar", Profit:1500, Expenses:500}
]);
]]></mx:Script>
<mx:ColumnChart id="myChart" dataProvider="{expenses}">
<mx:horizontalAxis>
<mx:CategoryAxis
dataProvider="{expenses}"
categoryField="Month"
/>
</mx:horizontalAxis>
<mx:series>
<mx:ColumnSeries
xField="Month"
yField="Profit"
displayName="Profit"
/>
<mx:ColumnSeries
xField="Month"
yField="Expenses"
displayName="Expenses"
/>
</mx:series>
</mx:ColumnChart>
<mx:Legend dataProvider="{myChart}"/>
</mx:Module>

Compiling modules

You compile the module as you would compile any Flex application using the mxmlc command-line compiler or the Flex Builder compiler. The following command is the simplest mxmlc command:

mxmlc MyModule.mxml

The result is a SWF file that you load into your application as a module. You cannot run the module-based SWF file as a stand-alone Flash application or load it into a browser window. It must be loaded by an application as a module.

Subtopics

Controlling module size
Recompiling modules

Controlling module size

Module size varies based on the components and classes that are used in the module. By default, a module includes all framework code that its components depend on, which can cause modules to be large by linking classes that overlap with the application's classes.

To reduce the size of the modules, you can instruct the module to externalize classes that are included by the application. This includes custom classes and framework classes. The result is that the module only includes the classes it requires, while the framework code and other dependencies are included in the application.

To externalize framework classes, you generate a linker report from the application that loads the modules, by using mxmlc commands. You then use this report as input to the module's load-externs compiler option.

To create a linker report:

  1. Generate the linker report:
    mxmlc -link-report=report.xml MyApplication.mxml
  2. Compile the application SWF file:
    mxmlc MyApplication.mxml
  3. Compile the module:
    mxmlc -load-externs=report.xml MyModule.mxml

Recompiling modules

You must recompile the modules if you make changes. Recompiling the main application does not trigger a recompilation of the modules. Similarly, if you change the application file, you do not have to recompile the modules, unless you make changes that might affect the linker report or common code.

NOTE

 

If you externalize the module's dependencies by using the load-externs option, your module might not be compatible with future versions of Adobe Flex. You might be required to recompile the module. To ensure that a future Flex application can use a module, compile that module with all the classes it requires. This also applies to applications that you load inside other applications.


MXML-based modules can load other modules. Those modules can load other modules, and so on.

Loading and unloading modules

To load and unload modules you use the load() and unload() methods of the ModuleLoader class. These methods take no parameters; the ModuleLoader loads or unloads the module that matches the value of the current url property.

The following example loads and unloads the module when you click the button:

<?xml version="1.0"?>
<!-- modules/ASModuleLoaderApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.modules.*;

public function createModule(m:ModuleLoader, s:String):void {
if (!m.url) {
m.url = s;
return;
}
m.loadModule();
}

public function removeModule(m:ModuleLoader):void {
m.unloadModule();
}
]]>
</mx:Script>

<mx:Panel title="Module Example"
height="90%"
width="90%"
paddingTop="10"
paddingLeft="10"
paddingRight="10"
paddingBottom="10"
>
<mx:TabNavigator id="tn"
width="100%"
height="100%"
creationPolicy="auto"
>
<mx:VBox id="vb1" label="Column Chart Module">
<mx:Button
label="Load"
click="createModule(chartModuleLoader, l1.text)"
/>
<mx:Button
label="Unload"
click="removeModule(chartModuleLoader)"
/>
<mx:Label id="l1" text="ColumnChartModule.swf"/>
<mx:ModuleLoader id="chartModuleLoader"/>
</mx:VBox>

<mx:VBox id="vb2" label="Form Module">
<mx:Button
label="Load"
click="createModule(formModuleLoader, l2.text)"
/>
<mx:Button
label="Unload"
click="removeModule(formModuleLoader)"
/>
<mx:Label id="l2" text="FormModule.swf"/>
<mx:ModuleLoader id="formModuleLoader"/>
</mx:VBox>
</mx:TabNavigator>
</mx:Panel>
</mx:Application>

Setting the location of a ModuleLoader triggers a call to the loadModule() method, too. This occurs when you first create a ModuleLoader with the url property set. It also occurs if you change the value of that property.

The following example loads the modules without calling the loadModule() method because the url property is set on the <mx:ModuleLoader> tags:

<?xml version="1.0"?>
<!-- modules/URLModuleLoaderApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Panel
title="Module Example"
height="90%"
width="90%"
paddingTop="10"
paddingLeft="10"
paddingRight="10"
paddingBottom="10"
>

<mx:Label width="100%" color="blue"
text="Select the tabs to change the panel."/>

<mx:TabNavigator id="tn"
width="100%"
height="100%"
creationPolicy="auto"
>
<mx:VBox id="vb1" label="Column Chart Module">
<mx:Label id="l1" text="ColumnChartModule.swf"/>
<mx:ModuleLoader url="ColumnChartModule.swf"/>
</mx:VBox>

<mx:VBox id="vb2" label="Form Module">
<mx:Label id="l2" text="FormModule.swf"/>
<mx:ModuleLoader url="FormModule.swf"/>
</mx:VBox>

</mx:TabNavigator>
</mx:Panel>
</mx:Application>

When you load a module, Flex ensures that there is only one copy of a module loaded, no matter how many times you call the load() method for that module.

Modules are loaded into the child of the current application domain. You can specify a different application domain by using the applicationDomain property of the ModuleLoader class.

When two classes of the same name but different implementations are loaded, the first one loaded is the one that is used.

Subtopics

Loading modules from different servers

Loading modules from different servers

To load a module from one server into an application running on a different server, you must establish a trust between the module and the application that loads it.

To allow access across domains:

  1. In your loading application, you must call the allowDomain() method and specify the target domain from which you load a module. So, specify the target domain in the preinitialize event handler of your application to ensure that the application is set up before the module is loaded.
  2. 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.
  3. Load the cross-domain file on the remote server in the preinitialize event handler of your loading application.
  4. In the loaded module, call the allowDomain() method so that it can communicate with the loader.

The following example shows the init() method of the loading application:

public function setup():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);
}

The following example shows the loaded module's init() method:

public function initMod():void {
Security.allowDomain("loaderservername");
}

The following example shows the cross-domain file that resides on the remote server:

<!-- crossdomain.xml file located at the root of the server -->
<cross-domain-policy>
<allow-access-from domain="loaderservername" to-ports="*"/>
</cross-domain-policy>

For more information about using the cross-domain policy file, see Applying Flex Security in Building and Deploying Flex 2 Applications.

Using ModuleLoader events

The ModuleLoader class triggers several events, including setup, ready, loading, unload, progress, error, and urlChanged. You can use these events to track the progress of the loading process, and find out when a module has been unloaded or when the ModuleLoader's target URL has changed.

Subtopics

Using the error event
Using the progress event

Using the error event

The error event gives you an opportunity to gracefully fail when a module does not load for some reason. In the following example, you can load and unload a module by using the Button controls. To trigger an error event, change the URL in the TextInput control to a module that does not exist. The error handler displays a message to the user and writes the error message to the trace log.

Revision 1/10/2007: Minor change to createModule() method.

<?xml version="1.0"?>
<!-- modules/ErrorEventHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.*;
import mx.controls.Alert;

private function errorHandler(e:ModuleEvent):void {
Alert.show("There was an error loading the module." +
" Please contact the Help Desk.");
trace(e.errorText);
}

public function createModule():void {
if (chartModuleLoader.url == ti1.text) {
// If they are the same, call loadModule.
chartModuleLoader.loadModule();
} else {
// If they are not the same, then change the url,
// which triggers a call to the loadModule() method.
chartModuleLoader.url = ti1.text;
}
}

public function removeModule():void {
chartModuleLoader.unloadModule();
}

]]>
</mx:Script>

<mx:Panel title="Module Example"
height="90%"
width="90%"
paddingTop="10"
paddingLeft="10"
paddingRight="10"
paddingBottom="10"
>
<mx:HBox>
<mx:Label text="URL:"/>
<mx:TextInput width="200" id="ti1" text="ColumnChartModule.swf"/>
<mx:Button label="Load" click="createModule()"/>
<mx:Button label="Unload" click="removeModule()"/>
</mx:HBox>
<mx:ModuleLoader id="chartModuleLoader" error="errorHandler(event)"/>
</mx:Panel>
</mx:Application>

Using the progress event

You can use the progress event to track the progress of a module as it loads. When you add a listener for the progress event, Flex calls that listener at regular intervals during the module's loading process. Each time the listener is called, you can look at the bytesLoaded property of the event. You can compare this to the bytesTotal property to get a percentage of completion.

The following example reports the level of completion during the module's loading process. It also produces a simple progress bar that shows users how close the loading is to being complete.

<?xml version="1.0"?>
<!-- modules/SimpleProgressEventHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import flash.events.ProgressEvent;
import mx.modules.*;

[Bindable]
public var progBar:String = "";
[Bindable]
public var progMessage:String = "";

private function progressEventHandler(e:ProgressEvent):void {
progBar += ".";
progMessage =
"Module " +
Math.round((e.bytesLoaded/e.bytesTotal) * 100) +
"% loaded";
}

public function createModule():void {
chartModuleLoader.loadModule();
}

public function removeModule():void {
chartModuleLoader.unloadModule();
progBar = "";
progMessage = "";
}
]]>
</mx:Script>

<mx:Panel title="Module Example"
height="90%"
width="90%"
paddingTop="10"
paddingLeft="10"
paddingRight="10"
paddingBottom="10"
>
<mx:HBox>
<mx:Label id="l2" text="{progMessage}"/>
<mx:Label id="l1" text="{progBar}"/>
</mx:HBox>

<mx:Button label="Load" click="createModule()"/>
<mx:Button label="Unload" click="removeModule()"/>

<mx:ModuleLoader
id="chartModuleLoader"
url="ColumnChartModule.swf"
progress="progressEventHandler(event)"
/>
</mx:Panel>
</mx:Application>

You can also connect a module loader to a ProgressBar control. The following example creates a custom component for the ModuleLoader that includes a ProgressBar control. The ProgressBar control displays the progress of the module loading.

<?xml version="1.0"?>
<!-- modules/MySimpleModuleLoader.mxml -->
<mx:ModuleLoader xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function clickHandler():void {
if (!url) {
url="ColumnChartModule.swf";
}
loadModule();
}
]]>
</mx:Script>

<mx:ProgressBar
id="progress"
width="100%"
source="{this}"
/>
<mx:HBox width="100%">
<mx:Button
id="load"
label="Load"
click="clickHandler()"
/>
<mx:Button
id="unload"
label="Unload"
click="unloadModule()"
/>
<mx:Button
id="reload"
label="Reload"
click="unloadModule();loadModule();"
/>
</mx:HBox>
</mx:ModuleLoader>

You can use this module in a simple application, as the following example shows:

<?xml version="1.0"?>
<!-- modules/ComplexProgressEventHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*">

<mx:Panel title="Module Example"
height="90%"
width="90%"
paddingTop="10"
paddingLeft="10"
paddingRight="10"
paddingBottom="10"
>
<mx:Label text="Use the buttons below to load and unload
the module."/>
<local:MySimpleModuleLoader id="customLoader"/>
</mx:Panel>

</mx:Application>

This example does not change the ProgressBar's label property for all events. For example, if you load and then unload the module, the label property remains at "LOADING 100%". To adjust the label properly, you must define other event handlers for the ModuleLoader events, such as unload and error.

posted on 2008-08-21 15:33 gembin 阅读(950) 评论(0)  编辑  收藏 所属分类: Flex


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

常用链接

留言簿(6)

随笔分类(440)

随笔档案(378)

文章档案(6)

新闻档案(1)

相册

收藏夹(9)

Adobe

Android

AS3

Blog-Links

Build

Design Pattern

Eclipse

Favorite Links

Flickr

Game Dev

HBase

Identity Management

IT resources

JEE

Language

OpenID

OSGi

SOA

Version Control

最新随笔

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜

free counters