ItemRenderer性能优化

http://rss.9ria.com/?p=3640 

DataGrid和AdvancedDataGrid应该是Flex企业项目中最常用的组件了,今天开始写一些优化技巧,这些技巧直接影响DataGrid的渲染效率。 

ItemRenderer优化。 

ItemRenderer是我们在扩展DataGrid单元格功能时需要扩展开发最多的东西,网络上有很多ItemRenderer的例子,但是大部分来说都是从方便开发的角度来使用的ItemRenderer而忽略了效率问题。那么到底何种情况是看似没问题,但实际上却牺牲了效率的呢?比如: 


1. 我们需要显示一个图片Icon,然后紧接着显示一个label。也许我们会使用下面这样的代码(摘自Adobe开发者博客2008年的一篇文章, http://www.adobe.com/devnet/flex/articles/itemrenderers_pt1.html) 

Java代码
  收藏代码
  1. <mx:DataGrid x="29" y="303" width="694" height="190" dataProvider="{testData.book}" variableRowHeight="true">  
  2.     <mx:columns>  
  3.         <mx:DataGridColumn headerText="Pub Date" dataField="date" width="85" />  
  4.         <mx:DataGridColumn headerText="Author" dataField="author" width="125"/>  
  5.         <mx:DataGridColumn headerText="Title" dataField="title">  
  6.             <mx:itemRenderer>  
  7.                 <mx:Component>  
  8.                     <mx:HBox paddingLeft="2">  
  9.                         <mx:Script>  
  10.                         <![CDATA[  
  11.                             override public function set data( value:Object ) : void {  
  12.                                 super.data = value;  
  13.                                 var today:Number = (new Date()).time;  
  14.                                 var pubDate:Number = Date.parse(data.date);  
  15.                                 if( pubDate > today ) setStyle("backgroundColor",0xff99ff);  
  16.                                 else setStyle("backgroundColor",0xffffff);  
  17.                             }  
  18.                         ]]>  
  19.                         </mx:Script>  
  20.                         <mx:Image source="{data.image}" width="50" height="50" scaleContent="true" />  
  21.                         <mx:Text width="100%" text="{data.title}" />  
  22.                     </mx:HBox>  
  23.                 </mx:Component>  
  24.             </mx:itemRenderer>  
  25.         </mx:DataGridColumn>  
  26.     </mx:columns>  
  27. </mx:DataGrid>   


这样写从正确与否的角度说完全没有问题,我们可以有两种写法,最简单的就是上面这样,在标签内直接写Itemrenderer。第二种的是创建一个新mxml文件继承于HBox取名叫XXXXRenderer,然后加入Image和Text控件,这种分离的写法也适合动态创建columns时使用。 

但是不管是哪种,都已经忽略了效率问题 (咱们今天的重点)。在Itemrenderer里使用Container的子类是很消耗资源的做法,相反高效的做法是直接继承UIComponent,在UIComponent里加入Image和Text控件。效率问题在小数据量,只有几列Column的时候是不容易发现的。但是如果你需要一次显示千条甚至万条的数据的,多列column都包含复杂Itemrenderer的话,效率问题就不得不考虑的(你也可以考虑为每个客户购置牛逼的机器)。就这个例子使用UIComponent来说,你会感觉出来Flex在渲染Datagrid时“假死”的时间会缩短,如果你机器太好,感觉不是很明显的话,尝试滑动滚动条,滚动条的平滑程度很真实的反应了两种情况下grid每个Cell的创建时间。 

下面是我用UIComponent创建同样ItemRenderer的代码 

Java代码
  收藏代码
  1. package renderer  
  2. {  
  3.     import mx.controls.Label;  
  4.     import mx.controls.Text;  
  5.     import mx.controls.dataGridClasses.DataGridListData;  
  6.     import mx.controls.listClasses.BaseListData;  
  7.     import mx.controls.listClasses.IDropInListItemRenderer;  
  8.     import mx.controls.listClasses.IListItemRenderer;  
  9.     import mx.core.IDataRenderer;  
  10.     import mx.core.UIComponent;  
  11.     import mx.core.UIComponentGlobals;  
  12.     import mx.events.FlexEvent;  
  13.     import mx.managers.ILayoutManagerClient;  
  14.     import mx.styles.IStyleClient;  
  15.    
  16.     import spark.components.Image;  
  17.    
  18.     public class DataGridExampleRenderer extends UIComponent implements IListItemRenderer,IDropInListItemRenderer  
  19.     {  
  20.    
  21.    
  22.         private var _listData:DataGridListData;  
  23.         private var _data:Object;  
  24.         private var text:Text;  
  25.         private var img:Image;  
  26.    
  27.    
  28.         public function DataGridExampleRenderer()  
  29.         {  
  30.             super();  
  31.         }  
  32.    
  33.    
  34.         override protected function createChildren():void{  
  35.             super.createChildren();  
  36.             text = new Text();  
  37.             img = new Image();  
  38.             this.addChild(text);  
  39.             this.addChild(img);  
  40.         }  
  41.    
  42.         override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{  
  43.             super.updateDisplayList(unscaledWidth,unscaledHeight);  
  44.             text.setActualSize(unscaledWidth/2,unscaledHeight);  
  45.             img.setActualSize(unscaledWidth/2,unscaledHeight);  
  46.             text.move(unscaledWidth/2,0);  
  47.         }  
  48.    
  49.         override protected function commitProperties():void  
  50.         {  
  51.             super.commitProperties();  
  52.             if(listData){  
  53.                 text.text = data[(listData as DataGridListData).dataField];  
  54.                 img.source = data.img;  
  55.             }else{  
  56.                 text.text = ""  
  57.             }  
  58.    
  59.    
  60.         }  
  61.    
  62.         [Bindable("dataChange")]  
  63.         public function get data():Object  
  64.         {  
  65.             return _data;  
  66.    
  67.         }  
  68.    
  69.         public function set data(value:Object):void  
  70.         {  
  71.             _data = value;  
  72.             invalidateProperties();  
  73.             dispatchEvent(new FlexEvent("dataChange"));  
  74.         }  
  75.    
  76.    
  77.    
  78.    
  79.         public function get listData():BaseListData  
  80.         {  
  81.             return _listData;  
  82.         }  
  83.    
  84.    
  85.         public function set listData(value:BaseListData):void  
  86.         {  
  87.             _listData = DataGridListData(value);  
  88.    
  89.         }  
  90.    
  91.    
  92.     }  
  93. }   


以上是第一种情况,咱们看第二种。 

2. 习惯性的使用Label, Text, TextArea来作为ItemRenderer来方便改变样式,比如背景,HTML显示等。 

比如这个例子http://blog.flexexamples.com/2007/08/20/formatting-a-flex-datagrid-control-using-a-custom-item-renderer/ 

非常正确的代码,但是却是影响效率的做法,不管是DataGridItemRenderer或者AdvancedDataGridItemRenderer. 它们是继承于UITextField. 相较于Label, Text或者TextArea来说。相当的轻量级,所以我们只需要继承于DataGridItemRenderer或者AdvancedDataGridItemRenderer,对它就行扩展同样可以实现样式改变,HTML显示的功能。 

上面博客中是这么写的 

Java代码
  收藏代码
  1. package {  
  2.     import mx.controls.Label;  
  3.     import mx.controls.listClasses.*;  
  4.    
  5.     public class PriceLabel extends Label {  
  6.    
  7.         private const POSITIVE_COLOR:uint = 0x000000// Black  
  8.         private const NEGATIVE_COLOR:uint = 0xFF0000// Red  
  9.    
  10.         override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {  
  11.             super.updateDisplayList(unscaledWidth, unscaledHeight);  
  12.    
  13.             /* Set the font color based on the item price. */  
  14.             setStyle("color", (parseFloat(data.@price) <= 0) ? NEGATIVE_COLOR : POSITIVE_COLOR);  
  15.         }  
  16.     }  
  17. }   


而从优化效率的角度来说,可以有个简单的方法这么写,继承DataGridItemRenderer,覆盖validateProperties.(我没实际运行过,不过肯定是没问题的) 

Java代码
  收藏代码
  1. override public function validateProperties():void  
  2.     {  
  3.         super.validateProperties();  
  4.         if (listData)  
  5.         {  
  6.             var grid:DataGrid = DataGrid(listData.owner);  
  7.             var column:DataGridColumn = grid.columns[listData.columnIndex];  
  8.    
  9.             htmlText = parseFloat(data.@price) <= 0"<font color='#ff0000'>"+data[column.dataField]+"</font>":data[column.dataField];  
  10.         }  
  11.     }   


总结起来的话就简单的两句点 

1. 不要使用Container做为ItemRenderer的父类,继承UIComponent. Container能做的,UIComponent也能做(多写一点代码) 
2. 如果只作为数据显示效果而使用ItemRenderer。不必继承label, Text或者TextArea. 直接继承DataGridItemRenderer或AdvancedDataGridItemRenderer进行扩展。 

下面的demo展示了我所说的第一种情况的AdvancedDataGrid的执行效率。左边是使用了UIComponent,右边使用了第一段代码的方式。为了使差别更明显,我在每个Renderer里放置了两张图片,并且显示了3列,1万条数据,虽然左边的滚动条滑动速度也不是很流畅,但是相对于右边来说差别已经很明显了。右键查看源代码 

http://www.flextheworld.com/demo/grid-itemrenderer/Test.html (0) 

Java代码  收藏代码
  1. <mx:DataGridColumn dataField="atc" headerText="攻击" itemRenderer="OurItemRenderer" />  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值