AS3应用程序模块化开发与ApplicationDomain
当程序越来越大,我们需要把它拆分成多个swf,在需要的时候动态加载。拆分时应该尽量把不同的类编译进唯一的swf,避免因swf文件增多而使整个程序的文件尺寸增大。按此原则可以拆分出以下两种swf,借助 ApplicationDomain 共享其代码和资源。
ApplicationDomain 是存放AS3定义(包括类、方法、接口等)的容器。使用Loader类加载swf时可以通过指定 ApplicationDomain 参数将swf加载到不同的域(Domain):
var
loader
:
Loader
=
new
Loader
()
;
var context : LoaderContext = new LoaderContext () ; /* 加载到子域(模块) */ context . applicationDomain = new ApplicationDomain ( ApplicationDomain . currentDomain ) ; /* 加载到同域(共享库) */ context . applicationDomain = ApplicationDomain . currentDomain ; /* 加载到新域(独立运行的程序或模块) */ context . applicationDomain = new ApplicationDomain () ; loader . load ( new URLRequest ( " loaded.swf " ) , context ) ; ApplicationDomain使用类似于显示列表(DisplayList)的树形结构。 相对于舞台(Stage) ,可以认为 ApplicationDomain 最根部的是系统域(system domain),包含 Flash Player 核心类定义。主程序所在的域(以下简称主域)就是它唯一的子域,类似于Stage下的文档类(Document Class)。
this
.
stage
.
addChild
(
mySprite
)
;
this . addChild ( myMC ) ; this . addChild ( myShape ) ; 运行后的显示列表: ApplicationDomain 的类似结构:
模块加载到同域不是一样可以吗?为何要加载到子域呢?好处就在于,卸载一个加载到子域的模块时,只要确保清除所有到该模块的引用,模块的所有类定义将被垃圾回收(Garbage Collection)。
ApplicationDomain 的 hasDefinition() 方法判断某定义是否存在,getDefinition() 方法获取指定的定义。下面以一个 例子 来介绍 ApplicationDomain 的具体用法和应用程序的拆分。
private
function
showModule
(
p_module
:
IModule
)
:
void
{ ?? ? if ( this . m_moduleList [ 0 ] == " login.swf " ) ?? ? { ?? ? ? ? p_module . show ( this ) ; ?? ? ? ? p_module . addEventListener ( " login " , this . onLogin ) ; ?? ? } else ?? ? { ?? ? ? ? p_module . show ( this , this . m_userName ) ; ?? ? } } 模块“继承”了主程序和共享库的所有类和资源,可以通过 ApplicationDomain.currentDomain.getDefinition() 来获取相应的类。注意获取不存在的类会抛出一个 ReferenceError。
protected
function
getClass
(
p_name
:
String
)
:
Class
{ ?? ? try ?? ? { ?? ? ? ? return ApplicationDomain . currentDomain . getDefinition ( p_name ) as Class ; ?? ? } catch ( p_e : ReferenceError ) ?? ? { ?? ? ? ? trace ( " 定义 " + p_name + " 不存在 " ) ; ?? ? ? ? return null ; ?? ? } ?? ? return null ; } 登录模块获取库中的界面元素,并在点击按钮后抛出事件。Event类不允许带参数,必须使用继承Event的自定义事件抛出参数。主程序可以把模块的自定义事件也编译进去(这样就增大了整个程序的文件尺寸),或者让监听模块事件的函数接受一个Objcet参数,以获取其动态属性。
private
function
onLogin
(
p_e
:
Object
)
:
void
{ ?? ? this . m_userName = p_e . userName ; ?? ? var login : IModule = p_e . currentTarget ; ?? ? login . removeEventListener ( " login " , this . onLogin ) ; ?? ? login . dispose () ; ?? ? this . loadSwf () ; } 主程序收到事件之后卸载注册模块,加载“结果模块”到子域,并将登录模块传出的”userName”参数传给结果模块。
public
function
show
(
p_parent
:
DisplayObjectContainer
,...
rest
)
:
void
{ ?? ? var libClass : Class = this . getClass ( " net.eidiot.appDomainDemo.Libaray " ) ; ?? ? if ( libClass != null ) this . initUi ( libClass , rest ) ; } override protected function initUi ( p_libClass : Class , p_rest : Array = null ) : void { ?? ? this . addUi ( this . getClass ( p_libClass . BG_NAME ) , " 结果 " ) ; ?? ? var resultFunc : Function = p_libClass . getResult ; ?? ? var userName : String = p_rest [ 0 ] ; ?? ? this . addChild ( resultFunc ( userName )) ; } 注意initUi()方法分别使用了共享库中Libaray类的静态属性BG_NAME和静态方法getResult()。但是直接调用此静态方法会报错,可以先用 resultFunc 变量取出此方法。详细内容请参考 源代码。 ?
使用 ApplicationDomain 类ApplicationDomain 类的用途是存储 ActionScript 3.0 定义表。SWF 文件中的所有代码被定义为存在于应用程序域中。 可以使用应用程序域划分位于同一个安全域中的类。这允许同一个类存在多个定义,并且还允许子级重用父级定义。 在使用 Loader 类 API 加载用 ActionScript 3.0 编写的外部 SWF 文件时,可以使用应用程序域。(请注意,在加载图像或用 ActionScript 1.0 或 ActionScript 2.0 编写的 SWF 文件时不能使用应用程序域。)包含在已加载类中的所有 ActionScript 3.0 定义都存储在应用程序域中。加载 SWF 文件时,通过将 LoaderContext 对象的 package { import flash.display.Loader; import flash.display.Sprite; import flash.events.*; import flash.net.URLRequest; import flash.system.ApplicationDomain; import flash.system.LoaderContext; public class ApplicationDomainExample extends Sprite { private var ldr:Loader; public function ApplicationDomainExample() { ldr = new Loader(); var req:URLRequest = new URLRequest("Greeter.swf"); var ldrContext:LoaderContext = new LoaderContext(false,ApplicationDomain.currentDomain); ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,completeHandler); ldr.load(req,ldrContext); } private function completeHandler(event:Event):void { ApplicationDomain.currentDomain.getDefinition("Greeter"); var myGreeter:Greeter = Greeter(event.target.content); var message:String = myGreeter.welcome("Tommy"); trace(message); // Hello,Tommy } } } 使用应用程序域时,还要记住以下几点:
下图显示了某个应用程序在单个域 (domain1.com) 中加载多个 SWF 文件的内容。根据加载内容的不同,可以使用不同的应用程序域。紧跟的文本说明用于为应用程序中的每个 SWF 文件设置适当应用程序域的逻辑。 ? 主应用程序文件为 application1.swf。它包含从其它 SWF 文件加载内容的 Loader 对象。在此方案下,当前域为 Application domain 1。用法 A、用法 B 和用法 C 说明了为应用程序中的每个 SWF 文件设置适当应用程序域的不同方法。用法 A:通过创建系统域的子级划分子级 SWF 文件。在示意图中,Application domain 2 创建为系统域的子级。application2.swf 文件在 Application domain 2 中加载,因此其类定义从 application1.swf 中定义的类中划分出来。 此方法的一个用处是使旧版应用程序能够动态加载相同应用程序的更新版本,而不会发生冲突。之所以不发生冲突,是因为尽管使用的是同样的类名称,但它们划分到不同的应用程序域中。 以下代码将创建作为系统域子级的应用程序域: request.url = "application2.swf"; request.applicationDomain = new ApplicationDomain(); 用法 B:在当前类定义中添加新的类定义。module1.swf 的应用程序域设置为当前域 (Application domain 1)。这可让您将新的类定义添加到应用程序的当前一组类定义中。这可用于主应用程序的运行时共享库。加载的 SWF 被视为远程共享库 (RSL)。使用此方法可以在应用程序启动之前使用预加载器加载 RSL。 以下代码将某应用程序域设置为当前域: request.url = "module1.swf"; request.applicationDomain = ApplicationDomain.currentDomain; 用法 C:通过创建当前域的新子域,使用父级的类定义。module3.swf 的应用程序域是当前域的子级,并且子级使用所有类的父级的版本。此方法的一个用处可能是作为一个使用主应用程序的类型的多屏幕丰富 Internet 应用程序 (RIA) 模块,该模块作为主应用程序的子级加载。如果能够确保所有类始终更新为向后兼容,并且正在加载的应用程序始终比其加载的软件的版本新,则子级将使用父级版本。如果可以确保不继续拥有对子级 SWF 的引用,则拥有了新的应用程序域还使您能够卸载所有的类定义以便于垃圾回收。 此方法使加载的模块可以共享加载者的 singleton 对象和静态类成员。 以下代码将创建当前域的新子域: request.url = "module3.swf"; request.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain); ?
实例效果演示
下载源文件 (rar 278K)
-----------------------------------------------------
getDefinition - 模块化你的程序
[ 2008-08-19 13:15:51 | 作者: L4cd.Net ]
字号:
大 |
中 |
小
为了加快程序的加载..
我们通常会把不同的功能模块做成不同的swf,要需要的时候再进行加载. 开始的时候..我们通常会直接使用loader加载,然后用addChild把loader显示出来.. 这样就完成了最简单的"模块"化了.. 当然进一步..我们会发现上面的方法已经满足不了我们的需求.. 有时候我们需要的不是一个实例对象,我们想得到的是一个类..让我们可以像调用自身库中的类一样可以实例化..复制..等等 这时候我们就可以使用ApplicationDomain(应用程序域),把加载进来的swf中的库的东西当自己的库一样使用 概念性的东西还是不好说... 直接看代码吧..下面的代码就是一个最简单的例子
//还是需要loader先进行加载
var loader:Loader = new Loader() loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderComplete) //sub.swf是一个外部swf,该swf库里有一个链接名叫"k_abc"元件 loader.load(new URLRequest("sub.swf")) function loaderComplete(e:Event):void{ ??//创建一个应用程序域 ??var app:ApplicationDomain = loader.contentLoaderInfo.applicationDomain ??//使用getDefinition返回sub.swf的库中链接名为k_abc的Class ??var c:Class = app.getDefinition("k_abc") as Class ??//接下来就不多说了..像普通的类一样操作就可以了... ??var a = new c() ??addChild(a) }
-----------------------------------------------
?Flex实时加载Skin
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |