惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cybersecurity and Infrastructure Security Agency CISA
月光博客
月光博客
Apple Machine Learning Research
Apple Machine Learning Research
量子位
Hugging Face - Blog
Hugging Face - Blog
罗磊的独立博客
小众软件
小众软件
T
Tailwind CSS Blog
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
The Exploit Database - CXSecurity.com
T
Tenable Blog
博客园 - 叶小钗
宝玉的分享
宝玉的分享
P
Privacy International News Feed
T
Tor Project blog
博客园_首页
AWS News Blog
AWS News Blog
雷峰网
雷峰网
C
Cisco Blogs
Help Net Security
Help Net Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 【当耐特】
T
Threat Research - Cisco Blogs
Last Week in AI
Last Week in AI
K
Kaspersky official blog
人人都是产品经理
人人都是产品经理
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
Schneier on Security
博客园 - Franky
W
WeLiveSecurity
L
LINUX DO - 热门话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
爱范儿
爱范儿
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Proofpoint News Feed
大猫的无限游戏
大猫的无限游戏
腾讯CDC
L
Lohrmann on Cybersecurity
J
Java Code Geeks
美团技术团队
博客园 - 司徒正美
The Cloudflare Blog
V
V2EX

博客园 - Morris

C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(673,5): error MSB3491: 未能向文件 - Morris as3 addEventListener各参数详解 在Flash中管理鼠标右键 Java与Action Script(Flash)类型对照 WinAPI--Win32 系统入口函数介绍 JavaScript 取得目前所在分割FRAME的寬度 用 FLASH CS5 作一個於 FLEX 可控制的 SWC 組件 Flash 創建好的 SWC 組件,如何在 FLEX 作一UI、簡單測試 Develop Android APP in Flash CS5 How to use Flex WebService Component in Flash Generate a iPhone certificate signing request on Windows 动态命名影片剪辑 Associative arrays 訪問父MOVIECLIP下的所有依序列號命名的子MOVIECLIP - Morris - 博客园 心跳模拟 CodeSmith基础(一) - Morris - 博客园 AS2.0中实现数据结构-哈希表 Alcon 使用方式重點 Flash AS2 同 VB.NET 類似的 WITH 寫法
flash AS3应用程序模块化开发与ApplicationDomain
Morris · 2010-11-02 · via 博客园 - Morris

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

  • 模块(Module)
    按照程序逻辑,可以拆分出多个“功能模块”,如“注册”、“管理”等等;按照游戏或社区类程序的关卡或场景,可以拆分出不同的“场景模块”。这些模块不是主程序运行必须的,只在需要的时候加载。
  • 运行时共享库(RSL)
    主场景或者多个模块通用的资源,比如位图、声音、设计好的页面元素等,可作为“库”在主程序运行前加载。可以整套更换的皮肤(skin)只需先加载一套。
      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)。
  一个fla文档类里代码:

this.stage.addChild(mySprite);
this.addChild(myMC);
this.addChild(myShape);

  运行后的显示列表:

  ApplicationDomain 的类似结构:

  • 加载到子域(模块)
    类似于“继承”,子域可以直接获得父域所有的类定义,反之父域得不到子域的。和继承关系不同的是,如果子域中有和父域同名的类,子域定义会被忽略而使用父域的定义。
  • 加载到同域(运行时共享库)
    类似集合里的合并关系。被加载swf里的所有类定义被合并到当前域中可以直接使用。和加载到子域相同,和当前域同名的定义也会被忽略。
  • 加载到新域(独立运行的程序或模块)
    swf载入指定域之前,先要检查该域及其父域中是否存在同名类,重复定义一概忽略。如果加载别人写的程序,或者使用旧版本的主程序加载新版本的模块,为避免类名冲突就要加载到新域独立运行以使用自己的类。模块加载到同域不是一样可以吗?为何要加载到子域呢?好处就在于,卸载一个加载到子域的模块时,只要确保清除所有到该模块的引用,模块的所有类定义将被垃圾回收(Garbage Collection)。
  • 有两种方式可以访问 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)一样操作加载的模块:监听事件、调用方法。因为编译器不会识别未定义的类,为使用强类型,建议为主类和模型定义相应的 接口,使用少量的重复代码协助编程。

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;
	ar userName : String = p_rest[0];
	this.addChild(resultFunc(userName));
}

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