主要参考书目:
《ADOBE FLEX3 DEVELOPER GUIDE》
《Flex.3.Language.Reference.cn.chm》
《FLEX3 COOKBOOK》
建议阅读本文档时,参考附件中源码FlexModule(已在FLEX BUILDER3+FLEX SDK3.2下编译通过)。
相关Module网址 : http://www.iteye.com/topic/297813
一、Module使用背景
Module是Adobe为解决Flex应用初始化时较大的下载负载问题而设计的一种折中方案。将主Application合理分割为多个Module后,配合延迟加载策略,就可以保证主Application在初始化只加载必要的资源从而减少等待时间。未被访问的Module默认将不被加载,这样在首次访问它们时会需要额外的等待时间,当然我们也可以在监听主Application加载完毕事件中将这些Module提前载入或者直接取消使用延迟加载策略以保证Module的响应时间。
二、Module相关类和接口简介
与Module相关的类和接口如下:
(1)mx.modules.Module->LayoutContainer->Container->UIComponent
(2)mx.modules.ModuleBase->EventDispatcher->Object
(3)mx.modules.ModuleLoader->VBox->Box->Container->UIComponent
(4)mx.modules.ModuleManager->Object
(5)mx.modules.IModuleInfo->IEventDispatcher
(6)mx.event.ModuleEvent->ProgressEvent->Event->Object
(7)mx.core.IFlexModuleFactory
1、Module和ModuleBase
Module类是一个容器,继承自FlexSprite,引入了一些框架代码,而ModuleBase类则继承自EventDispatcher。因此,如果我们的Module需要可视化元素,则扩展Module;反之则扩展ModuleBase。ModuleBase由于不依赖任何框架代码,生成的模块体积会更小。
例如一个带有可供用户输入信息的输入框Module:
//FlexModule/AsContactList.as
package
{
import mx.containers.Form;
import mx.containers.FormItem;
import mx.controls.TextInput;
import mx.modules.Module;
public class ASContactList extends Module
{
private var _form:Form;
private var _firstNameItem:FormItem;
private var _lastNameItem:FormItem;
public function ASContactList()
{
super ();
this.percentWidth = 100;
this.percentHeight = 100;
}
override protected function createChildren():void
{
super.createChildren();
_form = new Form();
_firstNameItem = createInputItem( "FirstName:");
_lastNameItem = createInputItem( "LastName:");
_form.addChild( _firstNameItem );
_form.addChild( _lastNameItem );
addChild( _form );
}
private function createInputItem( label:String ):FormItem
{
var item:FormItem = new FormItem();
item.label = label;
item.addChild( new TextInput() );
return item;
}
}
}
例如一个含有greet,welcomeeBack方法的ModuleBase:
//FlexModule/EntryStateModule.as
package
{
import mx.modules.ModuleBase;
public class EntryStateModule extends ModuleBase
{
public function EntryStateModule()
{
}
public function greet( first:String, last:String ):String
{
return "Hello,"+ first + " "+ last + ".";
}
public function welcomeBack(first:String,last:String):String
{
return "Nice to see you again,"+ first + ".";
}
}
}
2、ModuleLoader
ModuleLoader是一个可视化的容器类,可动态加载或卸载扩展自Module或ModuleBase的SWF。其功能类似于mx.controls.SWFLoader组件,不同之处是被载入的SWF需要实现IFlexModuleFactory接口,这样做的目的是为了允许应用程序在运行期间动态载入模块化SWF而不需要在主应用程序中实现此接口,更多关于IFlexModuleFactory的内容请参见文中其它相关部分(在本文第六节 给Module减肥部分中,你可以看到一个继承自Sprite但却很莫名地要实现IFlexModuleFactory接口的“类Module”组件,其原因就在于此)。
ModuleLoader的url属性被指定或改变时,就会调用loadModule方法加载Module,但是当url=" "时则会调用unloadModule卸载Module。另外,在调用unloadModule方法时,ModuleLoader只是将相应Module的引用置为null释放内存,url属性值并未改变。强烈建议在使用moduleloader做切换时,先调用unloadModule()以确保调用loadModule()方法时只有一个对象。
ModuleLoader的事件如下:
(1)error
下载模块出错时调度。
(2)loading
ModuleLoader 开始加载URL时调度
(3)progress
下载模块的过程中调度。下载进程期间定期调度此模块。
(4)ready
模块完成下载时调度。
(5)setup
已下载了足够的模块内容,您可以获得有关模块的信息时调度。
(6)unload
卸载模块时调度。
(7)urlChanged
给ModuleLoader 新的URL时调度。
如下展示了一个自定义的ModuleLoader,分别对这七个事件进行了监听。值得一提的是,ModuleLoader对象实例可以直接作为ProgressBar的source属性值被使用。
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/CustomModuleLoader.mxml -->
<mx:ModuleLoader xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" creationComplete="init()">
<mx:Script>
<![CDATA[
public function init():void {
addEventListener("urlChanged", onUrlChanged);
addEventListener("loading", onLoading);
addEventListener("progress", onProgress);
addEventListener("setup", onSetup);
addEventListener("ready", onReady);
addEventListener("error", onError);
addEventListener("unload", onUnload);
standin = panel;
removeChild(standin);
}
public function onUrlChanged(event:Event):void {
if (url == null) {
if (contains(standin))
removeChild(standin);
} else {
if (!contains(standin))
addChild(standin);
}
progress.indeterminate=true;
unload.enabled=false;
reload.enabled=false;
}
public function onLoading(event:Event):void {
progress.label="Loading module " + url;
if (!contains(standin))
addChild(standin);
progress.indeterminate=true;
unload.enabled=false;
reload.enabled=false;
}
public function onProgress(event:Event):void {
progress.label="Loaded %1 of %2 bytes...";
progress.indeterminate=false;
unload.enabled=true;
reload.enabled=false;
}
public function onSetup(event:Event):void {
progress.label="Module " + url + " initialized!";
progress.indeterminate=false;
unload.enabled=true;
reload.enabled=true;
}
public function onReady(event:Event):void {
progress.label="Module " + url + " successfully loaded!";
unload.enabled=true;
reload.enabled=true;
if (contains(standin))
removeChild(standin);
}
public function onError(event:Event):void {
progress.label="Error loading module " + url;
unload.enabled=false;
reload.enabled=true;
}
public function onUnload(event:Event):void {
if (url == null) {
if (contains(standin))
removeChild(standin);
} else {
if (!contains(standin))
addChild(standin);
}
progress.indeterminate=true;
progress.label="Module " + url + " was unloaded!";
unload.enabled=false;
reload.enabled=true;
}
public var standin:DisplayObject;
]]>
</mx:Script>
<mx:Panel id="panel" width="100%">
<mx:ProgressBar width="100%" id="progress" source="{this}"/>
<mx:HBox width="100%">
<mx:Button id="unload"
label="Unload Module"
click="unloadModule()"
/>
<mx:Button id="reload"
label="Reload Module"
click="unloadModule();loadModule()"
/>
</mx:HBox>
</mx:Panel>
</mx:ModuleLoader>
主Application:
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/CustomModuleLoaderEventApp.mxml-->
<mx:Application xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
public var selectedItem:Object;
]]>
</mx:Script>
<mx:ComboBox
width="215"
labelField="label"
close="selectedItem=ComboBox(event.target).selectedItem"
>
<mx:dataProvider>
<mx:Object label="Select Coverage"/>
<mx:Object
label="Life Insurance"
module="insurancemodules/LifeInsurance.swf"
/>
<mx:Object
label="Auto Insurance"
module="insurancemodules/AutoInsurance.swf"
/>
<mx:Object
label="Home Insurance"
module="insurancemodules/HomeInsurance.swf"
/>
</mx:dataProvider>
</mx:ComboBox>
<mx:Panel width="100%" height="100%">
<CustomModuleLoader id="mod"
width="100%"
url="{selectedItem.module}"
/>
</mx:Panel>
<mx:HBox>
<mx:Button label="Unload" click="mod.unloadModule()"/>
<mx:Button label="Nullify" click="mod.url = null"/>
</mx:HBox>
</mx:Application>
上述代码中所使用的Module大致上是相同的,比如AutoInsurance
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/insurancemodules/AutoInsurance.mxml-->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
backgroundColor="#ffffff"
width="100%"
height="100%"
>
<mx:Label
x="147"
y="50"
text="Auto Insurance"
fontSize="28"
fontFamily="Myriad Pro"
/>
<mx:Form left="47" top="136">
<mx:FormHeading label="Coverage"/>
<mx:FormItem label="Latte Spillage">
<mx:TextInput id="latte" width="200" />
</mx:FormItem>
<mx:FormItem label="Shopping Cart to the Door">
<mx:TextInput id="cart" width="200" />
</mx:FormItem>
<mx:FormItem label="Irate Moose">
<mx:TextInput id="moose" width="200" />
</mx:FormItem>
<mx:FormItem label="Color Fade">
<mx:ColorPicker />
</mx:FormItem>
</mx:Form>
</mx:Module>
3、ModuleManager和IModuleInfo
ModuleManager作为模块的管理类,提供了预先加载模块的能力,它有一个重要方法getModule(url:String):IModuleInfo。
IModuleInfo是特殊模块句柄的接口,可以查询模块状态、获得模块内部 factory 以及加载或卸载模块。属性如下:
(1)data:Object
与给定URL的singleton IModuleInfo关联的用户数据。
(2)error:Boolean
如果加载模块期间发生错误,则标志显示为true。ModuleManager调度ModuleEvent.ERROR事件时此标志为true。
(3)factory:IFlexModuleFactory
模块中定义的IFlexModuleFactory实现。只有在调用ModuleEvent.SETUP事件(或IModuleInfo.setup()方法返回true)后,它才会显示为非null。此时可以调用IFlexModuleFactory.info()方法。一旦调度ModuleEvent.READY事件(或IModuleInfo.ready()方法返回true),就可以调用IFlexModuleFactory.create()方法。
(4)loaded:Boolean
如果已对此模块调用load()方法,则标志显示为true。
(5)ready:Boolean
如果可以充分加载模块以获得其关联IFlexModuleFactory实现的句柄以及调用其create()方法,则标志显示为true。
(6)setup:Boolean
如果可以充分加载模块以获得其关联IFlexModuleFactory实现的句柄以及调用其info()方法,则标志显示为true。
(7)url:String
与此模块关联的URL。URL可以是本地的也可以是远程的(如“MyImageModule.swf”或“http://somedomain.com/modules/MyImageModule.swf”)。如果是远程的,必须在模块域和加载它的应用程序之间建立信任关系。
IModuleInfo的方法如下:
(1)load(applicationDomain:ApplicationDomain = null, securityDomain:SecurityDomain = null):void
请求加载该模块。如果已加载该模块,则调用不起任何作用。否则,会开始加载模块,并在加载过程中调度 progress 事件。applicationDomain指正在其中执行代码的当前应用程序域,securityDomain指当前安全沙箱。
(2)publish(factory:IFlexModuleFactory):void
将接口发布到ModuleManager。这允许具有String句柄的factory中存在延迟(或去耦)subscriptions。使用以 publish:// 开始的URL来引用以此方式发布的factory。
(3)release():void
将当前的引用释放到模块中。这样不会卸载该模块,除非该模块没有其他打开的引用,并且ModuleManager设置为仅包括限制数目的加载模块。
(4)unload():void
卸载模块。如果模块中存在未完成的定义引用,则Flash Player和AIR都不会完全卸载此模块,而是将其作为垃圾回收。
需要说明的是,Module的swf文件和其他application swf一样,会一直被保存在浏览器的缓存中直至被周期性清除或缓存用尽无法再存入,这样做的好处在一些客户端频繁使用某些swf时尤为明显(在本文第七节 将SWF存入FLASH缓存,而不是浏览器缓存部分中,我们将看到更多相关的知识和应用)。在文首的Module使用背景一节中说到,如果主Apllication使用延迟加载策略,可以通过ModuleManager预先加载模块到浏览器缓存,即使此模块当前尚未被使用。下面是一个监听主Application创建完毕事件,在事件处理中使用IModuleInfo的load方法多线程加载将要使用的模块示例。
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/PreloadModulesApp.mxml-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="preloadModules()">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
import mx.modules.IModuleInfo;
private function preloadModules():void {
// Get a reference to the module's interface.
var info:IModuleInfo = ModuleManager.getModule("insurancemodules/LifeInsurance.swf");
info.addEventListener(ModuleEvent.READY, modEventHandler);
// Load the module into memory. The module will be
// displayed when the user navigates to the second
// tab of the TabNavigator.
info.load();
}
private function modEventHandler(e:ModuleEvent):void {
trace("module event: " + e.type); // "ready"
}
]]>
</mx:Script>
<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="Default Display Module">
<mx:Label id="l1" text="HomeInsurance.swf"/>
<mx:ModuleLoader url="insurancemodules/HomeInsurance.swf"/>
</mx:VBox>
<mx:VBox id="vb2" label="The Preload Module">
<mx:Label id="l2" text="LifeInsurance.swf"/>
<mx:ModuleLoader url="insurancemodules/LifeInsurance.swf"/>
</mx:VBox>
</mx:TabNavigator>
</mx:Panel>
</mx:Application>
4、ModuleEvent
ModuleEvent->ProgressEvent->Event->Object
ModuleEvent的五个常量如下:
(1)PROGRESS
当模块正在加载时触发,你可以访问模块的bytesLoaded和bytesTotal属性。
(2)SETUP
当有足够多的模块信息可用时触发。
(3)READY
当模块加载完成时触发。
(4)UNLOAD
当模块被卸载时触发。
(5)ERROR
当下载模块途中出现错误时触发。
5、mx.core.IFlexModuleFactory:
IFlexModuleFactory 接口提供引导 Flex 应用程序和动态加载的模块时应该使用的约定。调度complete事件之后,立即调用info()方法是合法的。当可安全调用create()方法时,功能良好的模块将调度ready事件。
公共方法有两个:
(1)public function create(... parameters):Object
factory 方法,要求定义的实例是模块已知的。您可以提供可选参数集,以便构建工厂根据输入内容更改它们创建的内容。传递null指示,如果可能的话,创建默认的定义。
(2)public function info():Object
返回包含模块已知的静态数据的键/值对块。此方法始终成功,但是可以返回空对象。
例如使用ModuleManager控制模块显示:
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/ModuleManagerApp.mxml-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" creationComplete="creationHandler();">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
import mx.modules.IModuleInfo;
private var _moduleInfo:IModuleInfo;
private function creationHandler():void
{
_moduleInfo = ModuleManager.getModule("insurancemodules/HomeInsurance.swf");
_moduleInfo.addEventListener( ModuleEvent.READY,moduleLoadHandler );
_moduleInfo.load();
}
private function moduleLoadHandler(evt:ModuleEvent):void
{
canvas.addChild( _moduleInfo.factory.create() as DisplayObject );
}
]]>
</mx:Script>
<mx:Canvas id="canvas" width="500" height="500" />
</mx:Application>
三、Module域
通常将模块载入一个子域,那么模块里面的类定义都不是application域的。比如第一个模块载入了类PopUpManager,那么整合Application中,它就成了PopUpManager的拥有者,因为像这种manager都是单例的,如果另外一个模块稍后要使用这个PopUpManager,就会引发运行时异常。
解决办法就是确保这些managers,比如PopUpManager和DragManager或者其他一些共享的服务是在application中定义的,这样就能确保所有模块都能够使用,代码如下:
import mx.managers.PopUpManager;
import mx.managers.DragManager;
private var popUpManager:PopUpManager;
private var dragManager:DragManager;
这项技术同时也被应用到组件中,当module第一次使用组件时,将在它自己的域中拥有这些组件的类定义。如果别的module试图使用这些已经被另一个module使用的组件,它的定义将会不能匹配到现存的定义中。因此,为了避免组件的定义不匹配,在主应用程序中创建组件的实例,让所有的module去引用。
但是这个坏处很明显,这些声明看起来莫名其妙,成为了一个个"木偶变量"。另一个解决方法是借助 ApplicationDomain 来共享这些代码和资源。在ModuleLoader 的creationComplete方法中加入moduleLoader.applicationDomain = ApplicationDomain.currentDomain; 表示将其加载到运行时库。对于使用ModuleManager,则可以在IModuleInfo的load方法里指定域。
四、Module通信
1、映射返回的引用对象
模块访问Application通过其parentApplication属性来引用;Application访问模块则是把mx.modules.ModuleLoader的child属性返回的DisplayObject或mx.modules.IModuleInfo.factory.create方法返回的Object映射为模块类。比如var myModule = moduleLoader.child as MyModule;或var myModule:MyModule = _moduleInfo.factory.create() as MyModule;至于模块访问模块则可以通过parentApplication访问到Application再进行中转。
为了让代码降低耦合,同时主应用程序能连接更多的类实例,最关键的是避免内存泄露和Module额外误编译导致文件体积增大等问题,我们需要使用接口来进行规范。比如var myModule = moduleLoader.child as IMyModule;或var myModule:MyModule = _moduleInfo.factory.create() as IMyModule;
下面是一个映射接口的例子,我们假定创建多个供用户输入信息的表单模块。虽然它们具有不同的外观,或者对数据执行了不同的操作,但是访问模块数据的方法却是一样的。
首先创建一个接口IUserEntry,列出用户信息相关的属性方法:
//FlexModule/IuserEntry.as
package
{
import flash.events.IEventDispatcher;
public interface IUserEntry extends IEventDispatcher
{
function getFullName():String;
function get firstName():String;
function set firstName(str:String):void;
function get lastName():String;
function set lastName(str:String):void;
}
}
然后创建实现此接口的Module:
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/ContactEntry.mxml-->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
implements="IUserEntry"
layout="vertical" width="100%" height="100%">
<mx:Metadata>
[Event (name="submit", type="flash.events.Event")]
</mx:Metadata>
<mx:Script>
<![CDATA[
private var _firstName:String;
private var _lastName:String;
public static const SUBMIT:String = "submit";
private function submitHandler():void
{
firstName = firstNameInput.text;
lastName = lastNameInput.text;
dispatchEvent(new Event( SUBMIT ));
}
public function getFullName():String
{
return _firstName + " "+ _lastName;
}
[Bindable]
public function get firstName():String
{
return _firstName;
}
public function set firstName( str:String ):void
{
_firstName = str;
}
[Bindable]
public function get lastName():String
{
return _lastName;
}
public function set lastName( str:String ):void
{
_lastName = str;
}
]]>
</mx:Script>
<mx:Form>
<mx:FormItem label="First Name:">
<mx:TextInput id="firstNameInput" width="100%" text="{firstName}"/>
</mx:FormItem>
<mx:FormItem label="Last Name:">
<mx:TextInput id="lastNameInput" width="100%" text="{lastName}"/>
</mx:FormItem>
<mx:Button label="submit" click="submitHandler();"/>
</mx:Form>
</mx:Module>
最后使用<mx:ModuleLoader>的child属性(或mx.modules.IModuleInfo.factory.create方法)实例访问实现IUserEntry模块的数据:
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/ModuleUseINterfaceApp.mxml-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:Script>
<![CDATA[
private var myModule:IUserEntry;
private function moduleReadyHandler():void
{
myModule = moduleLoader.child as IUserEntry;
myModule.firstName="firstName from app";
myModule.lastName="lastName from app";
myModule.addEventListener( "submit", submitHandler );
}
private function submitHandler( evt:Event ):void
{
welcomeField.text = 'Hello,'+myModule.getFullName();
trace( myModule.firstName + " "+ myModule.lastName );
}
]]>
</mx:Script>
<mx:ModuleLoader id="moduleLoader" url="ContactEntry.swf"
ready="moduleReadyHandler();"/>
<mx:Label id="welcomeField"/>
</mx:Application>
在这种通信方式中,我们只需要Module编译完成的swf文件和相应的接口说明即可。在主Application中,通过映射Module实现的接口得到不同Module对象的引用,然后调用get,set等接口中的方法即可完成通信。
2、通过url给Module传参数数据
在模块URL指定的SWF地址字符串后加上一些参数,当模块载入后即可使用其loaderInfo属性进行解析。
比如在url后追加了查询字符串的模块:
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/ModuleUseURLApp.mxml-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" creationComplete="creationHandler();">
<mx:Script>
<![CDATA[
private static const F_NAME:String = "Ted";
private static const L_NAME:String = "Henderson";
private function creationHandler():void
{
var params:String = "firstName="+ F_NAME +"&lastName="+ L_NAME;
moduleLoader.url = "NameModule.swf?"+ params;
}
]]>
</mx:Script>
<mx:ModuleLoader id="moduleLoader"/>
</mx:Application>
通过loaderInfo属性解析URL,获得传入的参数数据:
<?xml version="1.0" encoding="utf-8"?>
<!--FlexModule/NameModule.mxml-->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
width="400" height="300" layout="absolute"
creationComplete="creationHandler();">
<mx:Script>
<![CDATA[
import mx.utils.ObjectProxy;
[Bindable]
private var _proxy:ObjectProxy;
private function creationHandler():void
{
_proxy = new ObjectProxy();
var pattern:RegExp = /.*\?/;
var query:String = loaderInfo.url.toString();
query = query.replace( pattern, "");
var params:Array = query.split( "&");
for( var i:int = 0; i < params.length; i++ )
{
var keyVal:Array = ( params[i]).toString().split("=");
_proxy[keyVal[0]] = keyVal[1];
}
}
]]>
</mx:Script>
<mx:Text text="{'Hello,'+ _proxy.firstName + ' '+_proxy.lastName}" />
</mx:Module>
这种通信方式的具体思路是,在Module中拼接要跳转的其他Module地址和参数值,比如var url:String="eqm/updateSmall.swf?eqmID="+this.DG.selectedItem.eqmID as String;
this.parentApplication.jumpTo(url);
然后通过主Application进行中转。
public function jumpTo(toUrl:String):void
{
moduleLoader.url=toUrl;
moduleLoader.loadModule();
}
也可以不使用parentApplication这种不太合规范的属性,改为在Module中抛出携带参数的事件,在主Application中监听此事件,获取事件携带的参数值后传入将要跳转的另一个Module中。具体代码可参考通信方式1中的myModule.addEventListener( "submit", submitHandler );
也可以在主Application中抛出事件,在Module中进行监听,具体代码参见附件FlexModule中的GreenAndRedModuleApp.mxml(额外使用了DynamicEvent,参考网址:http://yakovfain.javadevelopersjournal.com/flex_best_practices_sketch_1_an_application_with_a_single_.htm)
五、使用连接报告优化Module
默认情况下,编译器会将模块所依赖的所有自定义组件和框架代码都编译进SWF文件中。这其中有很多代码是主程序和其它模块所共用的。我们可以使用link-report命令行参数生成一个连接报告文件来列出主程序依赖的类,然后在编译模块时再使用link-externs连接报告文件。
>mxmlc -link-report=report.xml MyApplication.mxml
>mxmlc -link-externs=report.xml MyModule.mxml
很显然,这样将会导致Module与目标Application产生“绑定”,即这个Module无法再被其他Application所使用(可以绑定到一个空的Application以实现多应用),因此在新建Module时需要注意其Optimize for application选项的设置。另外,右键项目选择Properties->Flex Modules也可进一步修改。
注意事项:
1 Module要想最小,一定要把其他依赖的Lib库设置成运行时共享库
2 编译主应用程序的时候,设置编译选项-keep-all-type-selectors=true,否则加载出来的模块,里面的部分组件会丢失样式,甚至报空指针错误
参考网址:http://www.iteye.com/topic/461032