• 块化加载,设置加载域


    块化加载,设置加载域

     

    当程序越来越大,我们需要把它拆分成多个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 ) ;

      运行后的显示列表:
    01.gif 
      ApplicationDomain 的类似结构:
    02.gif

    • 加载到子域(模块) 
      类似于“继承”,子域可以直接获得父域所有的类定义,反之父域得不到子域的。和继承关系不同的是,如果子域中有和父域同名的类,子域定义会被忽略而使用父域的定义。
    • 加载到同域(运行时共享库) 
      类似集合里的合并关系。被加载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 ;
        
     var userName : String = p_rest [ 0 ] ;
        
     this . addChild ( resultFunc ( userName )) ;
    }
  • 相关阅读:
    用python写一个魔塔50层怪物伤害计算器
    一个奇怪的方法解决华为ENSP模拟器路由器启动后命令行一直“#”的问题
    安卓数据库sqllite查看工具Android Debug Database使用教程
    GNS3错误’Could not start Telnet console with command 'Solar-PuTTY.exe‘
    解决从其他地方拷贝过来的Android项目在本机不能运行(报错)的问题
    python不换行输出
    哈希查找对比普通遍历查找所需时间
    第二个爬虫之爬取知乎用户回答和文章并将所有内容保存到txt文件中
    我的第一个爬虫之爬取搜狗壁纸并按分类存入本地文件夹
    What is Double 11 in China? Is it a famous festival?
  • 原文地址:https://www.cnblogs.com/xiayong123/p/3716950.html
Copyright © 2020-2023  润新知