1.4 Flash Player的工作模型
Flash Player主要由两大部件组成,如图1-4所示。
(点击查看大图)图1-4 Flash Player的构成 |
顾名思义,ActionScript虚拟机负责执行编译后的ActionScript字节码,而图形渲染引擎则用来绘制“显示列表”(Display List)中的图形对象。
1.4.1 Flash Player的帧执行模型
在Flash Player中,ActionScript字节码的执行与图形渲染是两个完全分离的过程。Flash Player播放每一帧时,都按以下步骤进行:
1)Flash Player发出事件(Event)。这些事件包括由Timer、Mouse、ENTER_FRAMES、URLLoader等对象所发出的事件。如果你不了解事件的概念,请阅读1.4.2节中的内容。
2)用户代码被执行。在这个阶段执行所有侦听第1步中Flash Player发出的事件的代码。这里的用户代码指的是ActionScript虚拟机以外的由开发者所编写的代码。在这里,Flex SDK也属于用户代码。
3)RENDER事件被派发。RENDER事件的派发是由用户代码中调用flash.display.Stage对象的invalidate()方法所引起的,Stage(舞台)是Flash中显示对象的根容器。关于显示对象和Stage请参照1.4.2节中的内容。从帮助文档和Flex组件源代码来看,invalidate()只是告知Flash Player当前的显示列表已经发生变化或者说已经失效,该方法并不直接派发RENDER事件,而是由Flash Player在渲染显示列表之前检查显示列表是否失效。如果显示列表已经失效,则会在渲染新显示列表前派发RENDER事件,给用户代码最后的执行机会。
4)最后的用户代码被执行。侦听第3步RENDER事件的代码在此处被执行,这是用户代码在渲染显示列表前最后更改显示列表的机会。在此阶段,用户代码调用Stage对象的invalidate()方法则不会再派发新的RENDER事件。在代码清单1-1中,我们在RENDER事件的侦听方法onRender中调用了stage.invalidate()方法,但没有侦听到RNEDER事件。如果在ENTER_FRAME事件的侦听方法中调用stage.invalidate()则会导致Flash Player派发RENDER事件。
代码清单1-1 invalidate()方法的用途
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
- layout="absolute" xmlns:ns1="*" width="660" height="415"
- frameRate="1"
- addedToStage="onAddToStage(event);" >
- <mx:Script>
- <![CDATA[
- private function onAddToStage(event:Event):void
- {
- this.stage.frameRate=1;
- this.stage.addEventListener(Event.RENDER,onRender);
- this.addEventListener(Event.ENTER_FRAME ,onEnterFrame);
- }
- private function onRender(event:Event):void
- {
- race("现在是渲染前的RENDER事件派发过程!");
- //在此处调用stage.invalidate()不会再派发RENDER事件
- if(this.stage)
- {
- this.stage.invalidate();
- }
- }
- private function onEnterFrame(event:Event):void
- {
- trace("现在进入新一帧");
- /** 如果去掉注释,下面代码会导致RENDER事件的派发。
- if(this.stage)
- {
- this.stage.invalidate();
- }
- */
- }
- ]]>
- </mx:Script>
- </mx:Application>
Flash Player渲染出最新的显示列表。渲染显示列表的过程中不会有任何用户代码被执行,这是一个黑箱操作,开发者无法参与。
Flash执行一帧的整个过程如图1-5所示。
至此,希望读者在心中牢记Flash执行每一帧所经历的三个阶段:
用户动作阶段
失效动作阶段
渲染动作阶段
(点击查看大图)图1-5 Flash Player执行帧中的渲染图形过程 |
根据SWF文件规范,每个SWF文件中都设定了帧的播放频率,即每秒播放的帧数,简称FPS(Frames Per Second)。读者不禁会问:“如果应用中某帧的ActionScript代码执行量较大,消耗较多的CPU时间,Flash Player会不会为了保证设定的FPS而漏掉该帧的一些执行代码呢?”答案是否定的。Flash Player不会漏掉帧中任何需要执行的代码和任何需要渲染的图形。有人把Flash Player看成一个弹性的跑道,执行ActionScript代码和渲染图形是跑道上的两个阶段,正常情况下,Flash Player按照SWF文件中的FPS设置去执行每一帧,当某帧中代码执行时间与渲染图形时间之和超过了FPS设定的时间,那么执行一帧的时间就会超过FPS设定的时间,如同弹性跑道发生了变形。图1-6形象地展示了Flash Player的弹性跑道模型。
(点击查看大图)图1-6 Flash Player的弹性跑道模型 |
因此,SWF文件中设定的FPS是开发者期望的最大帧播放速度,而不是帧的实际播放速度,帧的实际播放速度小于或者等于FPS。