塊化加載,設置加載域

塊化加載,設置加載域

 

當程序愈來愈大,咱們須要把它拆分紅多個swf,在須要的時候動態加載。拆分時應該儘可能把不一樣的類編譯進惟一的swf,避免因swf文件增多而使整個程序的文件尺寸增大。按此原則能夠拆分出如下兩種swf,藉助 ApplicationDomain 共享其代碼和資源。shell

  • 模塊(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文檔類裏代碼:app

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

  運行後的顯示列表:
01.gif 
  ApplicationDomain 的相似結構:
02.gifless

  • 加載到子域(模塊) 
    相似於「繼承」,子域能夠直接得到父域全部的類定義,反之父域得不到子域的。和繼承關係不一樣的是,若是子域中有和父域同名的類,子域定義會被忽略而使用父域的定義。
  • 加載到同域(運行時共享庫) 
    相似集合裏的合併關係。被加載swf裏的全部類定義被合併到當前域中能夠直接使用。和加載到子域相同,和當前域同名的定義也會被忽略。
  • 加載到新域(獨立運行的程序或模塊) 
    swf載入指定域以前,先要檢查該域及其父域中是否存在同名類,重複定義一律忽略。若是加載別人寫的程序,或者使用舊版本的主程序加載新版本的模塊,爲避免類名衝突就要加載到新域獨立運行以使用本身的類。

  模塊加載到同域不是同樣能夠嗎?爲什麼要加載到子域呢?好處就在於,卸載一個加載到子域的模塊時,只要確保清除全部到該模塊的引用,模塊的全部類定義將被垃圾回收(Garbage Collection)。
  有兩種方式能夠訪問 ApplicationDomain :dom

  • 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)同樣操做加載的模塊:監聽事件、調用方法。由於編譯器不會識別未定義的類,爲使用強類型,建議爲主類和模型定義相應的接口,使用少許的重複代碼協助編程。ide

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參數,以獲取其動態屬性。this

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」參數傳給結果模塊。spa

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   ))   ;
}
相關文章
相關標籤/搜索