當程序越來(lái)越大,我們需要把它拆分成多個(gè)swf,在需要的時(shí)候動(dòng)態(tài)加載。拆分時(shí)應該盡量把不同的類(lèi)編譯進(jìn)唯一的swf,避免因swf文件增多而使整個(gè)程序的文件尺寸增大。按此原則可以拆分出以下兩種swf,借助 ApplicationDomain 共享其代碼和資源。
ApplicationDomain 是存放AS3定義(包括類(lèi)、方法、接口等)的容器。使用Loader類(lèi)加載swf時(shí)可以通過(guò)指定 ApplicationDomain 參數將swf加載到不同的域(Domain):
ApplicationDomain使用類(lèi)似于顯示列表(DisplayList)的樹(shù)形結構。 相對于舞臺(Stage) ,可以認為ApplicationDomain 最根部的是系統域(system domain),包含 Flash Player核心類(lèi)定義。主程序所在的域(以下簡(jiǎn)稱(chēng)主域)就是它唯一的子域,類(lèi)似于Stage下的文檔類(lèi)(Document Class)。
一個(gè)fla文檔類(lèi)里代碼:
運行后的顯示列表:


模塊加載到同域不是一樣可以嗎?為何要加載到子域呢?好處就在于,卸載一個(gè)加載到子域的模塊時(shí),只要確保清除所有到該模塊的引用,模塊的所有類(lèi)定義將被垃圾回收(Garbage Collection)。
有兩種方式可以訪(fǎng)問(wèn) ApplicationDomain :
ApplicationDomain 的 hasDefinition() 方法判斷某定義是否存在,getDefinition() 方法獲取指定的定義。下面以一個(gè) 例子 來(lái)介紹 ApplicationDomain 的具體用法和應用程序的拆分。
本例有四個(gè)swf,shell.swf是主程序,lib.swf是共享庫,login.swf和result.swf分別是“登錄”和“結果”模塊,所有的視圖元件都在共享庫中。實(shí)際開(kāi)發(fā)時(shí)可能有很多庫,比如“位圖庫”、“音效庫”、“模型通用庫”等。“通用庫”里存放多個(gè)模塊共用的資源,比如此例中的背景元素。而各個(gè)模塊獨有的資源還是放在各自的swf中。
主程序首先將共享庫加載到同域,完成后將“登錄模塊”加載到子域。主程序可以像操作普通的視覺(jué)對象(DisplayObject)一樣操作加載的模塊:監聽(tīng)事件、調用方法。因為編譯器不會(huì )識別未定義的類(lèi),為使用強類(lèi)型,建議為主類(lèi)和模型定義相應的接口,使用少量的重復代碼協(xié)助編程。
模塊“繼承”了主程序和共享庫的所有類(lèi)和資源,可以通過(guò) ApplicationDomain.currentDomain.getDefinition() 來(lái)獲取相應的類(lèi)。注意獲取不存在的類(lèi)會(huì )拋出一個(gè) ReferenceError。
登錄模塊獲取庫中的界面元素,并在點(diǎn)擊按鈕后拋出事件。Event類(lèi)不允許帶參數,必須使用繼承Event的自定義事件拋出參數。主程序可以把模塊的自定義事件也編譯進(jìn)去(這樣就增大了整個(gè)程序的文件尺寸),或者讓監聽(tīng)模塊事件的函數接受一個(gè)Objcet參數,以獲取其動(dòng)態(tài)屬性。
主程序收到事件之后卸載注冊模塊,加載“結果模塊”到子域,并將登錄模塊傳出的”userName”參數傳給結果模塊。
注意initUi()方法分別使用了共享庫中Libaray類(lèi)的靜態(tài)屬性BG_NAME和靜態(tài)方法getResult()。但是直接調用此靜態(tài)方法會(huì )報錯,可以先用 resultFunc 變量取出此方法。詳細內容請參考 源代碼。
| 使用 ApplicationDomain 類(lèi) | |||
![]() | |||
![]() | |||
ApplicationDomain 類(lèi)的用途是存儲 ActionScript 3.0 定義表。SWF 文件中的所有代碼被定義為存在于應用程序域中。 可以使用應用程序域劃分位于同一個(gè)安全域中的類(lèi)。這允許同一個(gè)類(lèi)存在多個(gè)定義,并且還允許子級重用父級定義。
在使用 Loader 類(lèi) API 加載用 ActionScript3.0 編寫(xiě)的外部 SWF 文件時(shí),可以使用應用程序域。(請注意,在加載圖像或用 ActionScript 1.0 或 ActionScript2.0 編寫(xiě)的 SWF 文件時(shí)不能使用應用程序域。)包含在已加載類(lèi)中的所有 ActionScript 3.0 定義都存儲在應用程序域中。加載SWF 文件時(shí),通過(guò)將 LoaderContext 對象的 applicationDomain 參數設置為 ApplicationDomain.currentDomain,可以指定文件包含在 Loader 對象所在的相同應用程序域中。通過(guò)將加載的 SWF 文件放在同一個(gè)應用程序域中,可以直接訪(fǎng)問(wèn)它的類(lèi)。如果加載的 SWF 文件包含嵌入的媒體(可通過(guò)其關(guān)聯(lián)的類(lèi)名稱(chēng)訪(fǎng)問(wèn)),或者您要訪(fǎng)問(wèn)加載的 SWF 文件的方法,則這種方式會(huì )很有用。如以下示例所示:
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}}}使用應用程序域時(shí),還要記住以下幾點(diǎn):
下圖顯示了某個(gè)應用程序在單個(gè)域 (domain1.com) 中加載多個(gè) SWF 文件的內容。根據加載內容的不同,可以使用不同的應用程序域。緊跟的文本說(shuō)明用于為應用程序中的每個(gè) SWF 文件設置適當應用程序域的邏輯。

用法 A:通過(guò)創(chuàng )建系統域的子級劃分子級 SWF 文件。在示意圖中,Application domain 2創(chuàng )建為系統域的子級。application2.swf 文件在 Application domain 2 中加載,因此其類(lèi)定義從application1.swf 中定義的類(lèi)中劃分出來(lái)。
此方法的一個(gè)用處是使舊版應用程序能夠動(dòng)態(tài)加載相同應用程序的更新版本,而不會(huì )發(fā)生沖突。之所以不發(fā)生沖突,是因為盡管使用的是同樣的類(lèi)名稱(chēng),但它們劃分到不同的應用程序域中。
以下代碼將創(chuàng )建作為系統域子級的應用程序域:
request.url = "application2.swf";request.applicationDomain = new ApplicationDomain();
用法 B:在當前類(lèi)定義中添加新的類(lèi)定義。module1.swf 的應用程序域設置為當前域(Application domain 1)。這可讓您將新的類(lèi)定義添加到應用程序的當前一組類(lèi)定義中。這可用于主應用程序的運行時(shí)共享庫。加載的SWF 被視為遠程共享庫 (RSL)。使用此方法可以在應用程序啟動(dòng)之前使用預加載器加載 RSL。
以下代碼將某應用程序域設置為當前域:
request.url = "module1.swf";request.applicationDomain = ApplicationDomain.currentDomain;
用法 C:通過(guò)創(chuàng )建當前域的新子域,使用父級的類(lèi)定義。module3.swf的應用程序域是當前域的子級,并且子級使用所有類(lèi)的父級的版本。此方法的一個(gè)用處可能是作為一個(gè)使用主應用程序的類(lèi)型的多屏幕豐富 Internet應用程序 (RIA)模塊,該模塊作為主應用程序的子級加載。如果能夠確保所有類(lèi)始終更新為向后兼容,并且正在加載的應用程序始終比其加載的軟件的版本新,則子級將使用父級版本。如果可以確保不繼續擁有對子級 SWF 的引用,則擁有了新的應用程序域還使您能夠卸載所有的類(lèi)定義以便于垃圾回收。
此方法使加載的模塊可以共享加載者的 singleton 對象和靜態(tài)類(lèi)成員。
以下代碼將創(chuàng )建當前域的新子域:
request.url = "module3.swf";request.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
| 轉載自http://hi.baidu.com/ming871/blog ... 2979d5d439c916.html Flex實(shí)時(shí)加載Skin2008-08-13 21:36一篇翻譯的文章,來(lái)自 The Kiwi Project ,這種方法很有用,但是唯一的問(wèn)題就是,在加載皮膚的過(guò)程中,用戶(hù)等待的問(wèn)題。如果皮膚文件比較大,沒(méi)有加載上來(lái)之前,程序可以說(shuō)是無(wú)反應的,這樣需要我們以某種方式提醒用戶(hù)當前程序的工作。 實(shí)時(shí)加載 Flex 皮膚 目前,有很多關(guān)于如何在你的 Flex 程序中繪制皮膚的資源。 概述:Flex 支持兩種繪制皮膚的方法:貼圖和編程。貼圖皮膚是在Flash、Photoshop、Firework等軟件中創(chuàng )建皮膚資源圖像,然后將他們導入 (embed)到 Flex 程序中;編程皮膚是建立一個(gè)通過(guò)程序定義一個(gè)控件皮膚的 ActionScript 類(lèi)。你可能猜到,貼圖皮膚比較簡(jiǎn)單,編程皮膚可以實(shí)現更加豐富的效果。 這兩個(gè)方法都有一個(gè)共同的缺點(diǎn)是,皮膚資源(對于貼圖來(lái)說(shuō)是 SWF/PNG/GIF 等文件,對于編程來(lái)說(shuō)是那個(gè) AS 類(lèi))必須在程序編譯時(shí)就被包括。怎么改進(jìn)呢?在這篇文章中我將演示一個(gè)如何實(shí)時(shí)加載貼圖皮膚的巧妙方法。 為了使這個(gè)例子盡可能的簡(jiǎn)單,我僅建立一個(gè)只有一個(gè)按鈕的 Flex 程序,這個(gè)按鈕的皮膚是動(dòng)態(tài)添加的。本程序將實(shí)時(shí)取得一個(gè)皮膚 SWF 文件,加載皮膚,然后把它們應用到按鈕上。 第一步:為皮膚資源建立一個(gè)外殼 SWF 目的,有了這個(gè)外殼 SWF,我的 Flex 程序就可以實(shí)時(shí)加載皮膚中適當的資源 package { import flash.display.Sprite; public class Wrapper extends Sprite { [Embed(source="flex_skins. public var rbUpSkin: Class; [Embed(source="flex_skins.swf",symbol="RadioButton_downIcon")] public var rbDownSkin: Class; [Embed(source="flex_skins.swf",symbol="RadioButton_disabledIcon")] public var rbDisabledSkin: Class; [Embed(source="flex_skins.swf",symbol="RadioButton_overIcon")] public var rbOverSkin: Class; } } 譯者注:上面代碼需要用 mxmlc 編譯,不用使用 Flex Builder 去建項目。 第二步:將這個(gè)外殼 SWF 放到服務(wù)器上 Flex 程序需要從某個(gè)地方加載皮膚呀。 第三步:在 Flex 程序中使用 Loader 加載外殼 SWF 我建了一個(gè)比較實(shí)用的類(lèi) ClassLoader 來(lái)加載 SWF 文件,并且將其轉化為類(lèi)。以下是一些關(guān)鍵行: loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler); loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); ... request = new URLRequest(swfLib); var context ![]() context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain); loader.load(request, context); 第四步:從加載的 SWF 中生成類(lèi),然后實(shí)例化 var wrapperClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition(className) as Class; var wrapper:Object = new wrapperClass(); 第五步:利用 setStyle 應用皮膚 這個(gè)很簡(jiǎn)單了。 StyleManager.getStyleDeclaration("Button").setStyle("upSkin", wrapper.rbUpSkin); StyleManager.getStyleDeclaration("Button").setStyle("downSkin", wrapper.rbDownSkin); StyleManager.getStyleDeclaration("Button").setStyle("disabledSkin", wrapper.rbDisabledSkin); StyleManager.getStyleDeclaration("Button").setStyle("overSkin", wrapper.rbOverSkin); 第六步:運行程序 那么為什么要這么做呢?動(dòng)態(tài)的皮膚提供給你一個(gè)難以置信而格外有力的功能:你可以讓你的用戶(hù)在你的程序上使用他們自己的皮膚。想象一下一個(gè)像 Winamp 的 Flex Mp3 播放器。 開(kāi)發(fā)人員并不需要為程序建立一個(gè)皮膚庫,任何人都可以發(fā)布一個(gè) UI 通過(guò)設置皮膚 SWF (可能在一個(gè)配置窗口中)讓用戶(hù)選擇任一在社區中提供的皮膚。同樣重要的,開(kāi)發(fā)者也有能力來(lái)控制哪個(gè)皮膚可以被替換,哪個(gè)皮膚只能使用原來(lái)的皮膚(僅僅對 相應的控件調用 setStyle 即可)。最后,將皮膚放到程序的外面,可以有效的保持程序的體積不會(huì )太大,肯定要比包含皮膚時(shí)要小。 |
聯(lián)系客服