块化加载,设置加载域

块化加载,设置加载域

 

当程序愈来愈大,咱们须要把它拆分红多个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   ))   ;
}
相关文章
相关标签/搜索