SystemManager如何工作

Flex SystemManager类的职责

SystemManager类的职责是配置并启动Flex应用程序。SysemManager的一项重要工作就是实例化Application,并将Application实例添加到Flash Player的displayList中。它还被用作Flex应用中一些顶级元素(如 popups、tooltips、cursors等)的载体,除此之外,它也负责这些顶级元素的焦点(focus)管理。SystemManager实例化还你的Applicaion,并将它添加到Flash Player的displayList中。

当Flex SWF文件被客户端请求时,SWF文件会以“流”的形式不断流向客户端的Flash Player。我们说下这期间都发生些什么事情。

首先,Flex SWF是一个两帧动画。第一帧包含Systemmanager、Preloader、DownloadProgressBar类,还有其他一些相关的功能类。DownloadProgressBar控件是由Preloader类创建的,用来显示当前加载初始化的进度。因为第一帧不能太大,所以Flex SWF把剩下的东东都放在的第二帧了。第二帧包含的东东很多,有Flex框架的其他代码、Application的代码、还有Application的其他资源(如嵌入字体、图片等等)。通过使用这两帧,我们可以利用Flash Player内置的streaming(流)支持,在Flex框架代码、application代码、嵌入资源没有加载完成之前,用Preloader显示Flex SWF的加载进度。这和在FlashIDE中创建预加载很像。



需要注意的是,如果第一帧的字节没有完全加载,就不能访问第一帧上的类,尝试New 实例化的话会抛出运行时错误。在Flash IDE中的2帧实现可以参考另一篇文章“关于“为Actionscript导出”与“在第一帧导出””。

下面我们说一下Flex SWF被请求后都先后发生了什么事情。首先。第一帧的字节都“流”到客户端的Flash Player中后,Flash Player通过创建SystemManager实例来执行这些字节。SystemManager实例做的第一件事就是让动画停在第一帧,然后通过Preloader类创建DownloadProgressBar控件。然后DownloadProgressBar不断地检查从服务器的Flex SWF不断“流”进来的字节,并把加载进度体现在控件上。一旦所有的字节都“流”进来后,SystemManager实例会让动画走到第二帧,然后开始实例化Application。

Application实例被创建后,SystemManager实例马上执行一件相当重要的任务,那就是把Application实例的systemManager属性指向自己。这就是为什么在Application实例化以后,我们还能访问到systemManager实例。然后application实例就开始创建子空间。当application实例的子控件创建完成并设定尺寸、位置后,application发布creationComplete事件。creationComplete事件发布后,Preloader将删除DownloadProgressBar控件,systemManager实例则把application实例添加到flash Player的displayList中。

Application实例被添加到displayList后,application实例发布applicationComplete事件。到现在,flex应用程序就创建并配置好,可以运行了。

继续深入了解SystemManager

SystemManager类扩MovieClip,是个功能及其强劲的影片剪辑。它的详细职责如下:

l 创建并初始化preloader,显示应用Flex应用程序的加载进度;

l 管理运行时共享库(RSL)的加载;

l 管理模块(module)逻辑。如果SystemManager是SWF的root,它就知道它是个Flex App(Flex应用程序),如果不是SWF的root,它就知道它是个Flex module(Flex模块)。SystemManager必须在app和module之间进行事件通讯(如鼠标事件和键盘事件);

l 管理从Stage发布的Event.RESIZE事件;

l 管理嵌入字体列表;(关于字体嵌入,请看另一篇文章“字体嵌入及应用”);

l 初始化一些管理单例类(如ResourceManager和StylesManager);

l 管理顶级的应用程序窗口。SystemManager维护一个cursorChildren列表和popUpChildren列表。他们分别用作实现tooltips和pop-up windows。

l 一旦Flex SWF文件的所有代码都加载完毕,SystemManager创建你的Application的实例并调用此实例的initialize方法。

l 一旦application实例发布它的FlexEvent.CREATION_COMPLETE事件,SystemManager将此实例添加到stage上。这就是为什么在FlexEvent.CREATION_COMPLETE事件发布时,application实例中没有指向stage的引用。而其他的组件在FlexEvent.CREATION_COMPLETE时都有指向stage的引用。application实例在发布FlexEvent.APPLICATION_COMPLETE事件后,才有指向stage的引用。

显微镜下看SystemManager的工作细节

第一帧

l Stop();

l 监听Flash Player的Event.INIT事件

l Flash player发布Event.INIT事件

1. 获取root SystemManager(如果当前的systemManager不是SWF的root)

2. 监听Event.ENTER_FRAME事件

3. 创建preloader

4. preloader监听FlexEvent.PRELOADER_DOC_FRAME_READY事件

5. preloader监听Event.COMPLETE事件

6. 开始加载RTLs并等待

7. RTLs加载完毕,preloader发布FlexEvent.PRELOADER_DOC_FRAME_READY事件。

u 创建Timer,计划在100ms后执行nextFrame()函数。

8. preloader在发布FlexEvent.PRELOADER_DOC_FRAME_READY事件100ms后,preloader再发布Event.COMPLETE事件。

9. TimerEvent.TIMER事件发布,执行nextFrame()函数,触发Event.ENTER_FRAME事件。

注:相同颜色是对应的事件发布和事件监听。

第二帧

l 各种Managers初始化完毕

l Stage监听Event.RESIZE事件

l 创建Application的实例

l Application实例监听FlexEvent.CREATION_COMPLETE事件

l 执行nextFrame()函数

l Application发布FlexEvent.CREATION_COMPLETE事件

n 移除preloader

n 将application实例添加到Stage

n Application发布FlexEvent.APPLICATION_COMPLETE事件



在Flex中怎么会有这么多帧呢?

在Flex开发中,能在SWF的主时间轴上添加帧吗?当然可以。

通过使用一个没有文档说明的元标签(meta tag),我们可以的。此标签就是[Frame]。事实上它是 –frames编译选项的一个快捷方式。如果在Application类的顶部添加[Frame]元标签,Flex编译器会在Application类所在的帧的前面插入一帧,如果你在元标签中指定了factoryClass属性,Flex编译器会自动生成一个factoryClass属性指定的工厂类(factory class)的子类,然后将此子类放到新插入的帧上。打开mx.core.Application类,在顶部附件会看到这样的元标签:[Frame(factoryClass="mx.managers.SystemManager")]。这个元标签告诉Flex编译器在Application类所在的帧前插入一帧,然后再创建一个SystemManager类的子类,放到新插入的帧上。

你可以自定义自己的SystemManager类,只要它实现IflexModuleFactory接口,你的代码就会被编译。编译器会覆盖SystemManager类的info方法,返回一个包含Application信息的对象。这些Application信息包括在<s:Application>标签中定义的属性、嵌入字体列表、Application的名称等等。

通过[frame]元标签,你可以覆盖默认的SystemManager实现。如果此元标签出现在你的Application的基类,则会自动创建一个factoryClass属性指定的工厂类的子类。如果元标签直接出现在你的Application类中,编译器也能识别此元标签。实际上,在Application类中的元标签才是最终被使用的元标签。而编译器会不再为元标签中指定的工厂类创建子类了,而是直接使用它来创建第一帧。

题外话

在某种情况下,Flex应用程序可能有多个systemManager实例。比如说加载子模块时。你可以使用一下方法访问并管理这些systemManager实例。

import mx.managers.SystemManagerGlobals;

//top level list of system managers

var systemManagers:Array = SystemManagerGlobals.topLevelSystemManagers;

//length for efficiency

var lng:int = systemManagers.length;

for(var i:int = 0; i &lt; lng; i ++){

              //type with a wildcard because we may encounter systemManager or windowed system manager

              var sm:* = systemManagers[i];

              //logic

       }

}

你可能感兴趣的:(Flex)