本文和大家重点讨论一下Flex模块化开发的概念,模块可以让你将程序分割成几个片段或单元。主程序或“壳”,可以动态的加载其它需要的模块,不会在启动时加载所有的模块,也不会加载任何用户尚未进行交互的模块。
Flex模块化开发
模块是可以被一个程序加载和卸载的SWF文件。模块不能独立于程序运行,但是可以在任意数量的程序间共享。
模块可以让你将程序分割成几个片段或单元。主程序或“壳”,可以动态的加载其它需要的模块,不会在启动时加载所有的模块,也不会加载任何用户尚未进行交互的模块。当程序不再需要一个模块时,可以卸载模块来释放内存和资源。
Flex模块化程序有如下优点:
1.更小的初始阶段SWF文件下载量;
2.更短的加载时间
3.更好的封装程序的相关方面
模块的好处
模块是包含了一个IFlexModuleFactory类工厂的可动态加载的特殊类型的SWF。它允许一个程序在运行时加载代码并创建类实例,而不需要类实现被链接到主程序。
模块与运行时共享库(RSLs)的共同点在于都从程序中将代码分割到独立加载的SWF文件中。但模块比RLS更加灵活,因为模块可以在运行时动态的加载、卸载,且在程序外被编译。
两个常见的使用模块的场景是有着不同的用户路径的程序和一个门户(portal)程序。
模块API细节
模块通过一个标准接口实现了一个类工厂。类工厂的产品实现了一个被“壳”所感知的接口,或“壳”实现一个可以感知模块的接口。
通过使用公共接口定义,这些共享的接口可以减少“壳”与模块之间的硬依赖。这提供了类型安全的通讯,以及不会增加SWF文件长度的强制的抽象层。
下图展示了“壳”和模块的接口之间的关系:
ModuleManager管理被夹在的模块的集合,这些模块被加工为以模块URI为索引的单例的Map。加载一个模块将触发一系列事件使客户端可以监视模块的状态。模块总是只加载一次,但是之后的重加载还是会导读事件,所以客户端代码可以被简化,并且可放心的通过READY时间来感知模块的类工厂是否对用户可用。
ModuleLoader类是位于ModuleManagerAPI顶部的“薄层”(thinlayer)。ModuleLoader类是用于实现基于模块架构的最简单的类,而ModuleManager则提供了对模块更全面的控制。
模块的域
默认的,一个模块被加载进当前程序域的一个子域。你可以通过ModuleLoader类的applicationDomain定义一个不同的程序域。
因为一个模块被夹在到一个子域,它自己的泪定义不会在主程序的域中。例如,第一个模块通过加载PopUpManager类而成为在整个程序中PopUpManager类的拥有者,因为该模块使用SingletonManager注册了管理器。如果其他模块在之后尝试使用PopUpManager,AdobePlayer将抛出一个异常。
解决方案是确保例如PopUpManager和DragManager之类的管理器一级其他被共享的服务都被主程序定义(或者之后被记载到“壳”程序的域中)。当你将这些类中的而一个提升到“壳”中,这个类就可以被所有的模块使用。典型的,通过添加下面的脚本块来实现:
- importmx.managers.PopUpManager;
- importmx.managers.DragManager;
- privatevarpopUpManager:PopUpManager;
- privatevardragManager:DragManager;
这个技巧同样壳被应用于组件。模块首先使用属于其自身的且定义于其自身域中的组件。结果是,如果其他模块尝试使用一个已经被另一的模块所以用的组件,那么它的定义不会匹配已经存在的定义。要避免组件定义被错误的匹配,就要在主程序中创建一个组件的实力。这样,那个组件的定义将被主程序应用,并且可以被其他任何字域中的组件使用。
因为一个Flex模块在于加载它的程序相同的安全域中,当你在一个AIR程序中使用模块时,任何的模块SWF文件必须位于与主程序SWF文件相同的目录或位于主程序SWF文件所在目录的子目录中,以确保主程序SWF和模块SWF位于AIR程序的安全沙箱中。这一点可通过模块的路径不需要"../"记号来从程序目录或程序的某个子目录向外导航加以印证。
Flex模块化程序
要创建一个Flex模块化的程序,你要为每个模块创建独立的类,以及加载这些模块的程序。
创建一个Flex模块化程序
1.创建任意数量的模块。一个基于MXML的模块文件的根标记是<mx:Module>。基于ActionScript的模块继承自Module或ModuleBase类。
2.编译每个模块。你可以使用mxmlc命令行编译器或AdobeFlexBuilder内建的编译器进行编译。
3.创建一个Aplication类,可以是一个典型的根元素为<mx:Applicaton>的MXML文件,也可以是一个只有ActionScript的程序。
4.在Application文件中,使用<mx:ModuleLoader>标签来加载每个模块。你也可以使用mx.modules.ModuleLoader和mx.modules.ModuleManager类的方法来加载模块。
编写模块
模块是就像程序文件一样的泪。你可以在ActionScript中创建它们,也可以通过使用MXML标签扩展Flex类的方法创建它们,即:你可以在MXML或ActionScript中创建模块。
创建基于MXML的模块
要在一个MXML种创建模块,你需要通过创建一个根元素为<mx:Module>的MXML文件来mx.modules.Module类。在那个标签中,可以添加任意的命名空间。你必须在文件头包含XML类型生命标签,如下所示:
- <?xmlversionxmlversion="1.0">
- <mx:Modulexmlns:mxmx:Modulexmlns:mx="http://www.adobe.com/2006/mxml"width="100%"height="100%">
- <mx:Script>
- <![CDATA[
- importmx.collections.ArrayCollection;
- [Bindable]
- publicvarexpenses:ArrayCollection=newArrayCollection([
- {Month:"Jan",Profit:2000,Expenses:1500},
- {Month:"Feb",Profit:1000,Expenses:200},
- {Month:"Mar",Profit:1500,Expenses:500}
- ]);
- ]]>
- </mx:Script>
- <mx:ColumnChartidmx:ColumnChartid="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:LegenddataProvidermx:LegenddataProvider="{myChart}"/>
- </mx:Module>
在你编译一个模块后,你可以在一个程序或另一个模块中加载它。你可以用下面介绍的技巧来加载基于MXML的模块:
ModuleLoaderModuleLoader类提供了高层的处理模块的API。
ModuleManagerModuleManager类提供了较ModuleLoader更底层的处理模块的API。
创建基于ActionScript的模块
要在ActionScript中创建一个模块,你可以创建一个继承自mx.modules.Moddule类或mx.moduls.ModuleBase类的文件。
扩展Module类与在MXML文件中使用<mx:Module>标记的效果相同。如果你的模块与框架交互,就应该扩展这个类。这意味着将向显示列表添加对象,或与显示对象发生交互。
要查看一个扩展Module类的ActionScript类的例子,可以先创建一个根元素为<mx:Module>的MXML文件。当你编译这个文件的时候,将keep-generated-actionscript编译选项设定为true。Flex的编译器将在一个叫做generated的目录中保存生成的类。你将注意到生成的类中包含着一些你可能尚不了解的代码,其结果是你可能无法编写扩展Module类的基于ActionScript的模块,而是使用MXML文件的方式来代替。
如果你的模块不包含任何框架代码,你可以创建一个继承自ModuleBase的泪。如果你使用ModuleBse类,你的模块将比使用基于Module类的时候更小,因为它不包含任何依赖的框架代码。
下面的例子创建了一个简单的、不包含任何框架代码的,且继承自ModuleBase类的模块:
- package{
- importmx.modules.ModuleBase;
- publicclassSimpleModuleextendsModuleBase{
- publicfunctionSimpleModule(){
- trace("SimpleModulecreated");
- }
- publicfunctioncomputeAnswer(a:Number,b:Number):Number{
- returna+b;
- }
- }
- }
【编辑推荐】