Flash的fl组件和Flex的mx组件都有一个受保护方法callLater,callLater可以说是优化组件执行效率的一个杀手锏,极其有用。
拿Flash的fl组件为例,fl组件有个重绘方法redraw(),如果改变组件的大小,焦点的获得和丢失都会是组件重绘来呈现不同的状态。而组件是复杂的,重绘的开销很大。如果假想一个按钮执行以下程式来更改外观,并且每次的更改都触发redraw()方法执行,那它将执行3次重绘,很显然是不须要的。
1 | button.width= 200 ; |
2 | button.height= 28 ; |
3 | button.setStyle( "textFormat" ,myTextFormat); |
一个优化的方式是假设组件不会自动重绘,需要手动进行:
1 | button.width= 200 ; |
2 | button.height= 28 ; |
3 | button.setStyle( "textFormat" ,myTextFormat); |
4 | button.redraw(); |
这个方式不太友好,每次都要记得去重绘组件,幸运的是callLater解决了这个问题。
callLater把要执行的函数延迟到下一帧。所以对button的width更改后,它会记得在下一帧重绘自身,当然这一帧你还改变了height和样式,它也只是重复地记忆要在下一帧重绘自身。到了下一帧的时候,它执行一次redraw(),仅是一次。
Flex组件的基类UIComponent有110多个公开属性,90个公开方法,17个受保护方法,70多个事件,10多个样式,10多个效果,还有6个常量。一个基类都如此庞大,可想而知,优化是多么重要。
在Flex组件的callLater中,重绘被分割成了三个受保护的方法:
- commitProperties()
- measure()
- updateDisplayList()
职责的分割更加提高了效率,这些延迟执行都是callLater实现的。把callLater实现的细节抽取下来写成一个单独的类:
01
package
com.colorhook.tools{
02
03
/**
04
* @author colorhook
05
* @copyright http://www.colorhook.com
06
*/
07
08
import
flash.display.DisplayObject;
09
import
flash.utils.Dictionary;
10
import
flash.events.Event;
11
12
public
class
FrameCallLater
implements
ICallLater{
13
14
private
var
_target:DisplayObject;
15
private
var
methods:Dictionary;
16
private
var
inCallLaterPhase:
Boolean
=
false
;
17
18
public
function
FrameCallLater(target:DisplayObject){
19
this
._target=target;
20
methods=
new
Dictionary(
true
);
21
super
();
22
}
23
24
/**
25
* defined by ICallLater, I write a class TimeCallLater to implement it also.
26
*/
27
public
function
call(fun:Function):
void
{
28
if
(inCallLaterPhase||_target==
null
) {
return
; }
29
30
methods[fun]=
true
;
31
32
if
(_target.stage !=
null
) {
33
_target.stage.addEventListener(Event.RENDER,callLaterDispatcher,
false
,
0
,
true
);
34
_target.stage.invalidate();
35
}
else
{
36
_target.addEventListener(Event.ADDED_TO_STAGE,callLaterDispatcher,
false
,
0
,
true
);
37
}
38
}
39
40
private
function
callLaterDispatcher(event:Event):
void
{
41
if
(event.type == Event.ADDED_TO_STAGE) {
42
_target.removeEventListener(Event.ADDED_TO_STAGE,callLaterDispatcher);
43
_target.stage.addEventListener(Event.RENDER,callLaterDispatcher,
false
,
0
,
true
);
44
_target.stage.invalidate();
45
return
;
46
}
else
{
47
event.target.removeEventListener(Event.RENDER,callLaterDispatcher);
48
if
(_target.stage ==
null
) {
49
_target.addEventListener(Event.ADDED_TO_STAGE,callLaterDispatcher,
false
,
0
,
true
);
50
return
;
51
}
52
}
53
54
inCallLaterPhase =
true
;
55
56
for
(
var
method:
Object
in
methods) {
57
method();
58
delete
(methods[method]);
59
}
60
inCallLaterPhase =
false
;
61
}
62
63
public
function
get
target():DisplayObject{
64
return
_target;
65
}
66
67
}
68
}
*****************************************************找了很久的资料,才解决tree加载时显示所有节点这个问题,引自http://hi.baidu.com/lz0830/blog/item/7b406e82d7f41c98f703a632.html
该文中提出Tree的数据源在MXML文件中和数据源是从后台程序获取两种情况:
一、针对第一种情况(tree的数据源在MXML文件中)的写法:
private function initApp():void {
for each(var item:XML in this.myTree.dataProvider)
this.myTree.expandChildrenOf(item,true);
}该函数的调用creationComplete="initApp()"
二、数据源从后台程序获取:
<!-- 读取xml文件给tree绑定数据源 -->
<mx:HTTPService id="tree_httpsrv" url="assets/data/treeview.xml" result="setTree(event)" fault="faultOperation(event)" resultFormat="xml" /><!-- 读取xml文件的处理 -->
[Bindable]
private var tree_xml:XML;private function setTree(event:ResultEvent):void
{
tree_xml = XML(event.result);
var tree_data:XMLList = tree_xml.treeviewNode;
myTree.dataProvider = tree_data;
myTree.callLater(expandTree);
}private function expandTree():void
{
//expand all tree node
myTree.expandChildrenOf(tree_xml,true);
}