http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/ApplicationDomain.html#includeExamplesSummary
是談到當 main.swf 載入外部的 asset.swf 後,要使用 asset.swf 中的 Class 來動態產生物件時,要注意 ApplicationDomain 的設定。
在這個範例中最有意義的是 ClassLoader,透過這個好用的類別,你可以任意載入 *.swf,然後使用 function getClass(className:String):Class 取得在 asset.swf 中的類別,並產生物件。
我將這個 ClassLoader 類別作了一點點修改,當第一次載入完成後便會將 ByteArray 存在 cache 中,若是有不小心載入到同一個 *.swf 的話,就不會再從 server 作 request,而是從 cache 中找出之前載入過的 ByteArray 即可。
package
{
import flash.display.Loader;
import flash.errors.IllegalOperationError;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
public class ClassLoader extends EventDispatcher
{
public static var CLASS_LOADED:String = "classLoaded";
public static var LOAD_ERROR:String = "loadError";
private var loader:Loader;
private var swfLib:String;
private var request:URLRequest;
private var loadedClass:Class;
static private var cache:Object = new Object();
private var lib:String;
public function ClassLoader(lib:String)
{
this.lib = lib;
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,completeHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler);
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityErrorHandler);
}
public function load():void {
if(cache[lib]!=null){
loadFromCache();
}else{
var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, urlLoaderComplete);
urlLoader.load(new URLRequest(lib));
}
}
private function urlLoaderComplete(e:Event):void{
cache[lib] = (e.currentTarget as URLLoader).data;
loadFromCache();
}
private function loadFromCache(){
var ba:ByteArray = cache[lib] as ByteArray;
var context:LoaderContext = new LoaderContext();
context.applicationDomain=ApplicationDomain.currentDomain;
loader.loadBytes(ba, context);
}
public function getClass(className:String):Class {
try {
return loader.contentLoaderInfo.applicationDomain.getDefinition(className) as Class;
} catch (e:Error) {
throw new IllegalOperationError(className + " definition not found in " + swfLib);
}
return null;
}
private function completeHandler(e:Event):void {
dispatchEvent(new Event(ClassLoader.CLASS_LOADED));
}
private function ioErrorHandler(e:Event):void {
dispatchEvent(new Event(ClassLoader.LOAD_ERROR));
}
private function securityErrorHandler(e:Event):void {
dispatchEvent(new Event(ClassLoader.LOAD_ERROR));
}
}
}
要測試的話,可以先建立一個 asset.swf,裡面準備一個 MovieClip,放在 Library 中,設定其類別為 "MC1",並且是 "匯出在第 1 個影格",而場景或畫面上不用放置任何東西,基本上這個 asset.swf 的解析度或其他設定要設多少也都沒關係,因為我們真正會用到的就是那 第一影格會匯出 的類別們。
第二步,建一個 main.swf,在 frame 1 寫:
var clsLoader:ClassLoader = new ClassLoader("asset.swf");
clsLoader.addEventListener(ClassLoader.CLASS_LOADED, onLoaded);
clsLoader.load();
function onLoaded(e:Event):void{
var runtimeClassRef:Class = clsLoader.getClass("MC1");
var mc1:MovieClip = new runtimeClassRef() as MovieClip;
addChild(mc1);
}
測試後,應該可以發現 main 有將 asset 中的 MC1 類別產生出實體,並放在場景上。
2 意見:
我執行了這個程式出現以下錯誤訊息:
1119: Access of possibly undefined property data through a reference with static type.
Clascache[lib]=e.currentTarget as URLLoader.data;
請問是甚麼問題呢?感謝。
e.currentTarget as 後面應該要接一個 類別 (Class)、介面 (Interface),但是你接的卻是一個 object instance,所以會有問題
張貼意見