組件的失效機制

組件失效機制(invalidationmechanism)是Flex用來提高應用性能的一項技術,組件生命週期與佈局主要利用這一機制來實現,本節對該機制進行總結並探討該機制如何實現。

1. 什麼是組件失效機制

在組件的生命週期中,應用可能會改變組件的大小和位置,改變組件的屬性來控制組件的顯示,或者更改組件的樣式和皮膚屬性。比如,可能更改組件中所顯示文本(Text)的字體(font)。組件中文本字體發生變化,那麼組件的尺寸也可能隨之變化,這就會影響到組件的佈局。從前面的內容中我們可以知道,佈局操作會使Flex自動調用自定義組件的commitProperties()、measure(),layoutChrome()以及updateDisplayList()等一系列方法。

通過程序來更改“字體(font)”這個屬性值的執行速度遠遠快於Flex渲染圖形和更新屏幕的速度。因此,應該在確定最終字體之後再更新佈局。

當設置了組件的多個屬性後,每個屬性都可能影響到組件的尺寸,比如Button控件的label和icon屬性,開發者肯定希望所有屬性全部設置完成後一次性地執行commitProperties()、measure()和updateDisplayList()方法,而不是在設置完label屬性後執行一遍這些方法,然後在設置icon屬性後又執行一遍這些方法。

另外,可能會有多個組件同時改變字體,組件的字體改變都可能會引起組件尺寸的變化,從而影響它們之間的相對位置。這時應該讓Flex去協調佈局操作,以消除冗餘處理,而不是每個組件更新字體之後都執行一次佈局操作。

Flex使用失效機制來同步組件的變更。正如前面所講到的那樣,Flex用一系列方法的調用來標記組件的某些東西已經發生變化,然後將其延遲到下一次屏幕更新時通過佈局管理器統一調用組件的commitProperties()、measure()、layoutChrome()以及updateDisplayList()方法。

表2-1列出了組件中有關“失效(invalidation)”的方法。

表2-1 組件中“失效”方法列表

組件的失效機制



2. Flex如何實現“失效機制”

Flex通過UIComponent的callLater()方法實現組件的“失效機制”。callLater()方法聲明如下:
public function callLater(method:Function, args:Array =null):void

callLater是一個非常重要的底層方法,callLater方法將給定的method及其參數args放入內部隊列中,當下一次屏幕更新時調用內部隊列中的方法。那麼“下一次屏幕更新”指的是什麼呢?通過研究callLater方法的源代碼我們發現callLater方法主要做三件事情:

首先將需要延遲調用的method方法及其參數args放入組件的內部隊列中。

爲舞臺(Stage)對象的ENTER_FRAME和RENDER事件設置偵聽器,在這兩個事件的偵聽器中會調用在“內部隊列”中延遲的方法。隊列中的方法一旦被調用就會從隊列中清除。

調用舞臺(stage)對象的invalidate()方法,這樣FlashPlayer在顯示列表渲染前能夠派發RENDER事件。

因此,回顧圖1-5所示的“FlashPlayer執行幀中ActionScript代碼及渲染圖形過程”,我們可以得出以下結論:如果在“用戶動作”階段的代碼中調用callLater方法,則callLater方法中method參數所指定的方法將在“失效動作”階段被調用。如果在“失效動作”階段的代碼中調用callLater方法,則callLater方法中的method參數所指定的方法將在下一幀ENTER_FRAME事件派發時調用。

<?xml version="1.0"?>
<!-- CallLater.mxml -->
<mx:Applicationxmlns:mx="http://www.adobe.com/2006/mxml"
enterFrame="this.onEnterFrame(event)">
<mx:Script><![CDATA[
[Bindable]
public var text:String = "這是一串通過callLater方法實現滾動文字";
[Bindable]
//文字移動速度。
public var speed:Number = 5;
import flash.display.Stage
public function initTicker():void
{
//從右側開始移動文字
theText.move( this.width+10, 0 );
callLater(moveText);
}
private function onEnterFrame(event:Event):void
{
trace("----------------進入新一幀------------------------");
}
public function moveText():void
{
var xpos:Number = theText.x;
if( xpos-speed+theText.width < 0 )
{
xpos = this.width+10; //從右側開始移動文字
}
xpos -= speed;
//每幀應當執行兩次該代碼,分別在進入幀和渲染顯示列表前各執行一次。
trace(speed, xpos);
//該代碼的調用將導致顯示列表失效,從而RENDER事件被Flash派發。
theText.move(xpos,0);
// 如果下面代碼在"失效動作"階段執行,則moveText方法將
在進入新一幀時被調用。如果該代碼在進入新一幀時被調用,也
就是在"用戶動作"階段被調用,則moveText方法將在"失效動作"階
段執行,也就是在渲染顯示列表前執行。
callLater(moveText);
}
public function changeSpeed():void
{
speed = speedSelector.value;
}
]]>
</mx:Script>
<mx:Panel title="步進器例子" width="400"height="200">
<mx:Canvas creationComplete="initTicker()"
horizontalScrollPolicy="off"
backgroundColor="red" color="white"width="100%">
<mx:Label id="theText" text="{text}"y="0"/>
</mx:Canvas>
<mx:HBox>
<mx:Label text="速度:"/>
<mx:HSlider minimum="1" maximum="10"value="{speed}"
id="speedSelector" snapInterval="1" tickInterval="1"
change="changeSpeed()"/>
</mx:HBox>
</mx:Panel>
</mx:Application>

通過調試我們可以發現,在執行一幀的過程中,moveText()方法被執行兩次,因爲trace(speed,xpos)方法輸出了兩次。調試狀態下,控制檯輸入如下所示:
----------------進入新一幀------------------------
5 1025
----------------進入新一幀------------------------
5 1020
5 1015
----進入新一幀------------------------------------
5 1010
5 1005
----------------進入新一幀------------------------
......
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章