当前位置: 首页 > news >正文

AS3应用程序模块化开发与ApplicationDomain

当程序越来越大,我们需要把它拆分成多个swf,在需要的时候动态加载。拆分时应该尽量把不同的类编译进唯一的swf,避免因swf文件增多而使整个程序的文件尺寸增大。按此原则可以拆分出以下两种swf,借助ApplicationDomain共享其代码和资源。

模块(Module)
按照程序逻辑,可以拆分出多个“功能模块”,如“注册”、“管理”等等;按照游戏或社区类程序的关卡或场景,可以拆分出不同的“场景模块”。
这些模块不是主程序运行必须的,只在需要的时候加载

运行时共享库(RSL)

主场景或者多个模块通用的资源,比如位图、声音、设计好的页面元素等,可作为“库”在主程序运行前加载。可以整套更换的皮肤(skin)只需先加载一套。

----------------------------------------------
applicationDomain属性

publicvarapplicationDomain:ApplicationDomain=null
指定用于Loader.load()或Loader.loadBytes()方法的应用程序域。只应在加载使用ActionScript3.0编写的SWF文件 (不是图像或使用ActionScript1.0或ActionScript2.0编写的SWF文件)时才使用此属性。

每 个安全域被分成一个或多个由ApplicationDomain对象表示的应用程序域。应用程序域并不是用于安全目的;它们用于管 理ActionScript代码的协作单元。如果是从其它域加载SWF文件,并允许将它放置到另外一个安全域中,则您将无法控制所加载 的SWF文件被放置到哪个应用程序域中;即使您指定应选择某个应用程序域,也会忽略。但是,如果是将SWF文件加载到您自己的安全域中(因为 此SWF文件来自您自己的域,或者您正在将它导入到您的安全域中),您就可以控制为所加载的SWF文件选择哪个应用程序域。

在LoaderContext.applicationDomain中,您只可以传递您自己的安全域中的应用程序域。如果试图传递任何其它安全域中的应用程序域,则会引发SecurityError异常。

有四种ApplicationDomain属性可供您选择使用:

加 载器的ApplicationDomain的子级(模块)。默认值。可以使用语 法newApplicationDomain(ApplicationDomain.currentDomain)显式表示这种选择。这将允许所 加载的SWF文件直接使用父级的类,例如,可通过编写newMyClassDefinedInParent()来使用。但是父级则不能使用此 语法;如果父级要使用子级的类,它必须调用ApplicationDomain.getDefinition()来检索它们。
这种选择的优点是:
1、如果子级定义的类与父级已经定义的类同名,不会出现错误结果;
2、子级只会继承父级对该类的定义,除非子级或父级调用ApplicationDomain.getDefinition()方法来检索子级的冲突定义,否则将不使用此定义。

加载器自己的ApplicationDomain(共享库) 。使用ApplicationDomain.currentDomain时请使用此应用程序域。加载完成后,父级和子级可以直接使用对方的类。
如果子级试图定义的类与父级已经定义的类同名,将出现错误并放弃加载。

系 统ApplicationDomain的子级(独立运行的程序或模块)。使用newApplicationDomain(null)时请使用 此应用程序域。这将完全分离加载方和被加载方,从而允许它们使用相同的名称定义各自版本的类并且不会产生冲突或隐藏。一方查看另一方的类的唯一方式是 调用ApplicationDomain.getDefinition()方法。

其 它ApplicationDomain的子级。有时可能会有更复杂的ApplicationDomain层次结构。可以将SWF文件从您自 己的SecurityDomain加载到任何ApplicationDomain中。例 如,newApplicationDomain(ApplicationDomain.currentDomain.parentDomain.parentDomain)将SWF文 件加载到当前域父级的父级的新子级中。

加载完成后,为调 用ApplicationDomain.getDefinition(),任一方(加载方或被加载方)都可能需要找到它自己 的ApplicationDomain或另一方的ApplicationDomain。任一方都可以通过使 用ApplicationDomain.currentDomain来检索对它自己的应用程序域的引用。执行加载的SWF文件可以通 过Loader.contentLoaderInfo.applicationDomain来检索对被加载的SWF文件 的ApplicationDomain的引用。如果被加载的SWF文件知道自己的加载方式,则它可以找到执行加载的SWF文件 的ApplicationDomain对象。例如,如果子级是以默认方式被加载的,则它可以通过使 用ApplicationDomain.currentDomain.parentDomain找到执行加载的SWF文件的应用程序域。

----------------------------------------------
ApplicationDomain是存放AS3定义(包括类、方法、接口等)的容器。
使用Loader类加载swf时可以通过指定ApplicationDomain参数将swf加载到不同的域(Domain):

AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 代码
varloader:Loader = new Loader();
varcontext: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最根部的是系统域(systemdomain),包 含FlashPlayer核心类定义。主程序所在的域(以下简称主域)就是它唯一的子域,类似于Stage下的文档类 (DocumentClass)。
  
一个fla文档类里代码:
this.stage .addChild(mySprite);
this.addChild(myMC);
this.addChild(myShape);

  运行后的显示列表:

ApplicationDomain的类似结构:

加载到子域(模块)

类似于“继承”,子域可以直接获得父域所有的类定义,反之父域得不到子域的。和继承关系不同的是,如果子域中有和父域同名的类,子域定义会被忽略而使用父域的定义。

加载到同域(运行时共享库)

类似集合里的合并关系。被加载swf里的所有类定义被合并到当前域中可以直接使用。和加载到子域相同,和当前域同名的定义也会被忽略。

加载到新域(独立运行的程序或模块)

swf载入指定域之前,先要检查该域及其父域中是否存在同名类,重复定义一概忽略。如果加载别人写的程序,或者使用旧版本的主程序加载新版本的模块,为避免类名冲突就要加载到新域独立运行以使用自己的类。

  模块加载到同域不是一样可以吗?为何要加载到子域呢?好处就在于,卸载一个加载到子域的模块时,只要确保清除所有到该模块的引用,模块的所有类定义将被垃圾回收(GarbageCollection)。
  有两种方式可以访问ApplicationDomain:

  ApplicationDomain.currentDomain

  currentDomain是ApplicationDomain的静态变量,表示当前代码所在的域。该变量很奇特,在主程序里指向主域,在加载到子域的模块里则指向该模块所在的子域。虽然ApplicationDomain有个parentDomain 属 性,但子域已经自动获得了父域的类定义,所以通过ApplicationDomain.currentDomain就可以获取父域定义了——包括主程 序和加载到主域的共享库。(注:系统域不可直接访问,主域和所有新域即系统域子域的parentDomain属性为null)
  LoaderInfo类的applicationDomain属性
  此方式可以访问任何方式加载的swf的ApplicationDomain。对于主程序来说,加载到同域的库定义已经存在于ApplicationDomain.currentDomain,而模块的类主程序一般用不到。所以这种方式个人不推荐使用。
  ApplicationDomain的hasDefinition()方法判断某定义是否存在,getDefinition()方法获取指定的定义。下面以一个例子来介绍ApplicationDomain的具体用法和应用程序的拆分。
  本利有四个swf,shell.swf是主程序,lib.swf是共享库,login.swf和result.swf分别是“登录”和“结果”模块,所有的视图元件都在共享库中。
实际开发时可能有很多库,比如“位图库”、“音效库”、“模型通用库”等。“通用库”里存放多个模块共用的资源,比如此例中的背景元素。
而各个模块独有的资源还是放在各自的swf中。
   主程序首先将共享库加载到同域,完成后将“登录模块”加载到子域。主程序可以像操作普通的视觉对象(DisplayObject)一样操作加载的模块: 监听事件、调用方法。因为编译器不会识别未定义的类,为使用强类型,建议为主类和模型定义相应的接口,使用少量的重复代码协助编程。

AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 代码
private functionshowModule(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。

AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 代码
protected functiongetClass(p_name:String):Class
{
try
{
return ApplicationDomain.currentDomain.getDefinition(p_name)asClass;
}
catch (p_e:ReferenceError)
{
trace(
" 定义 " + p_name + " 不存在 " );
return null ;
}
return null ;
}


  登录模块获取库中的界面元素,并在点击按钮后抛出事件。Event类不允许带参数,必须使用继承Event的自定义事件抛出参数。主 程序可以把模块的自定义事件也编译进去(这样就增大了整个程序的文件尺寸),或者让监听模块事件的函数接受一个Objcet参数,以获取其动态属性。

AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 代码
private functiononLogin(p_e:Object): void
{
this .m_userName = p_e.userName;
varlogin:IModule
= p_e.currentTarget;
login.removeEventListener(
" login " , this .onLogin);
login.dispose();
this .loadSwf();
}


  主程序收到事件之后卸载注册模块,加载“结果模块”到子域,并将登录模块传出的”userName”参数传给结果模块。

AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 AS3应用程序模块化开发与ApplicationDomain - Davis - GotoAndPlay部落 代码
public functionshow(p_parent:DisplayObjectContainer, rest): void
{
varlibClass:Class
= this .getClass( " net.eidiot.appDomainDemo.Libaray " );
if (libClass != null )
this .initUi(libClass,rest);
}

override
protected functioninitUi(p_libClass:Class,p_rest:Array = null ): void
{
this .addUi( this .getClass(p_libClass.BG_NAME), " 结果 " );
varresultFunc:Function
= p_libClass.getResult;
varuserName:String
= p_rest[ 0 ];
this .addChild(resultFunc(userName));
}


  注意initUi()方法分别使用了共享库中Libaray类的静态属性BG_NAME和静态方法getResult()。但是直接调用此静态方法会报错,可以先用resultFunc变量取出此方法。

相关文章:

  • Access restriction: The type BASE64Encoder is not accessible due to restrict
  • 什么是x-window
  • Unity3D 关于yield在collider中的使用
  • ultraWinGrid绑定下拉框
  • 双向循环链表运用(2)
  • Qt ui的动态加载
  • Oracle11gR2 静默建库,删库和配置
  • Qt ui在程序中的使用
  • grub2编译安装
  • 项目中用到的架构模式(持续更新)
  • 校园招聘笔试题(A卷)
  • javadoc 命令
  • 校园招聘笔试题(B卷)
  • 进程与线程的一个简单解释
  • 嵌入式C开发人员的最好的0x10道笔试题
  • $translatePartialLoader加载失败及解决方式
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • const let
  • es6
  • ES学习笔记(12)--Symbol
  • Java基本数据类型之Number
  • Java知识点总结(JavaIO-打印流)
  • jdbc就是这么简单
  • js ES6 求数组的交集,并集,还有差集
  • node学习系列之简单文件上传
  • Redis 中的布隆过滤器
  • Redis字符串类型内部编码剖析
  • Redux 中间件分析
  • Travix是如何部署应用程序到Kubernetes上的
  • Wamp集成环境 添加PHP的新版本
  • 订阅Forge Viewer所有的事件
  • 读懂package.json -- 依赖管理
  • 简析gRPC client 连接管理
  • 2017年360最后一道编程题
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • 如何用纯 CSS 创作一个货车 loader
  • ​学习一下,什么是预包装食品?​
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (3)llvm ir转换过程
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (全注解开发)学习Spring-MVC的第三天
  • (三)模仿学习-Action数据的模仿
  • .Net Core和.Net Standard直观理解
  • .NET6 命令行启动及发布单个Exe文件
  • .net6使用Sejil可视化日志
  • .netcore 如何获取系统中所有session_ASP.NET Core如何解决分布式Session一致性问题
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • .NET面试题解析(11)-SQL语言基础及数据库基本原理