flash学习之 利用stage.invalidate()方法和render事件提高as3程序的运行效率

AS3中的DisplayObject有一个render事件,他会在重绘DisplayList之前触发,这给我们提供了在重绘之前最后一次操作的机会。
每次需要DisplayObject触发render事时,都要调用一次 stage.invalidate();

下面用一个小例子来说明一下具体用法把。
假设我们现在要写一个list组件,该组件有addItem()方法用于添加list项目,和remvoeItem( )   方法用于删除list项目,当然还可能有addItemAt( ) , removeItemAt ( ) 等方法,这些方法调用后,都需要对list内的显示对象进行重新排列。
我们先实现一个List类,用于显示列表项目
List类中,有addItem( )   和 removeItem( )   这两个方法提供给外部调用,用于添加和删除list项目,这两个方法中除了将列表项目添加/ 删除,还要调用一个方法来重新对list中的项目进行排列,layoutContents( )
关键就是,这个layoutContents( ) 的调用,他的调用次数越少,那效率当然就越高啦,如果是常规的做法,就是类似这样:

代码:

public   function   addItem ( item: DisplayObject) : void  
{  
    addChild( item) ;  
    layoutContents( ) ;  
}

将item加入后,重新排列列表

下面是List类的源代码:

代码:

package  {  
import flash. display. DisplayObject;  
import flash. display. Sprite;  
import flash. events. Event;  
public   class List  extends   Sprite 
{  
public   function   addItem ( item: DisplayObject) : void  
{  
    addChild( item) ;  
    layoutContents( ) ;  
}  
public   function   removeItem( item: DisplayObject) : void  
{  
    if ( contains( item) )  
    {
        removeChild( item) ;  
        layoutContents( ) ;  
    }  
}  

这个程序粗看似乎没什么问题,但却存在一个效率问题
如果只调用一次addItem,没问题,如果调用10次呢? 前9次的layoutcontents( ) 都不是必须的,只有第十次才是真正需要的这样程序的效率就降低了。
我们可以试一下

先需要一个简单的ListItem

代码:
package 
{  
import flash. display. Shape;  
public   class ListItem  extends   Shape 
{  
public   function   ListItem( )  
{  
    super ( ) ;  
    graphics. beginFill ( 0xFF6600) ;
    graphics. drawRect( 0,   0,   30,   16) ;  
    graphics. endFill ( ) ;
}  
}
}

然后测试
package  {
import flash. display. Sprite;
public   class ListTest  extends   Sprite  {
public   function   ListTest( )   {
    var   list : List  =   new   List( ) ;
    addChild( list ) ;
    list . addItem ( new   ListItem( ) ) ;
    list . addItem ( new   ListItem( ) ) ;
    list . addItem ( new   ListItem( ) ) ;
}
}
}

我们可以看到,输出了3次  do   layout 说明layoutcontents执行了3次,前两次都是多余的。
现在,解决办法就是利用render事件啦。
因为在当前帧内,显示列表更新前会触发render事件,所以在render事件触发后来排列列表项目,就可以保证排列方法在做了任意次的添加或删除操作后只需调用一次,从而提高效率。
这么做只需要对List类稍做一些改动,首先肯定是要监听render事件,我们可以仅监听stage对象的render事件即可,因为这样以后可以做一个独立的RepaintManger来管理所有组件的重绘(可以参考AsWing的RepaintManager类)。
在render事件触发后,做我们需要的调整,由于要render事件触发,就必须先调用stage. invalidate( )   ,所以每次添加或删除list项目后,都要执行一次该方法,即:
代码:
public   function   addItem ( item: DisplayObject) : voide  {
. . . . . .
stage. invalidate( )
}

由 于是监听的stage的render事件,所以在添加删除操作后,要做一个标记,表示list有改动,需要在render事件后重新排列,如果该标记为 false,那么即使render触发了也不做排列,因为stage的render事件也有可能是由于该stage内的其他child需要重绘而造成 stage的render触发。


下面是改过后的List代码
package  {
import flash. display. DisplayObject;
import flash. display. Sprite;
import flash. events. Event;
public   class List  extends   Sprite  {
private   var   changed: Boolean ;
public   function   List( )   {
    super ( ) ;
    addEventListener( Event. ADDED_TO_STAGE,   __addToStage) ;
}
public   function   addItem ( item: DisplayObject) : void   {
    addChild( item) ;
    requireLayout( ) ;
}
public   function   removeItem( item: DisplayObject) : void   {
    if ( contains( item) )   {
        removeChild( item) ;
        requireLayout( ) ;
    }
}
private   function   requireLayout( ) : void   {
    changed  =   true ;
    if ( stage  ! =   null )   stage. invalidate( ) ;
}
//对内部项目进行排列,可以是任意的排列算法
protected  function   layoutContents( ) : void   {
    trace ( "do layout" ) ;
    var   y: Number   =   0;
    var   num: int   =   numChildren;
    for ( var   i: int = 0;   inum;   i+ + )   {
        var   child: DisplayObject  =   getChildAt( i) ;
        child. x  =   0;
        child. y  =   y;
        y  + =   child. height + 2;
    }
}
private   function   __addToStage( e: Event) : void   {
    stage. addEventListener( Event. RENDER,   __render) ;
    if ( changed)   stage. invalidate( ) ;
}
private   function   __render( e: Event) : void   {
    if ( changed)   {
        layoutContents( ) ;
        changed  =   false ;
    }
}
}
}

当我们再次运行ListTest的时候,do layout 只输出了一次。
就是这些内容,当然,你可能会说,需要做到这些根本不需要这么复杂,只要公开layoutContents方法,在所有操作调用之后让调用者自行调用一次layoutContents( )
在这个例子中当然可以,但是当情况很复杂的时候,使用者每进行一次操作都要自行调用更新的方法,这样做并不是好的解决方案。试想,如果 flashplayer不会为我们处理显示DisplayObject的工作,而是每次addChild/ removeChild之后,我们都需要自行调用flashplayer底层的方法来让我们需要的东西显示出来,这样做显然很不好。
完了,就这些东东,写完之后俺感觉自己的表达能力不好,如果觉得我说的很模糊,那就研究下代码吧,全部代码都在上面了,欢迎指教和讨论  ^ ^

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值