Rendering The Fat


Published on

A look at how to create slim item renderers for large applications to keep performance up on DataGrid and AdvancedDataGrid in Flex 3.

Published in: Technology
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Rendering The Fat

  1. 1. Rendering the Fat:<br />How to Keep Your DataGrid Healthy<br />Ben Schmidtke III<br />Digital Primates<br /><br />Twitter: stunnedgrowth<br />
  2. 2. Who Am I<br />Ben Schmidtke III<br />Consultant - Digital Primates IT Consulting Group<br />Flash Platform Developer for 11 years<br />Adobe Certified Instructor<br />Twitter: stunnedgrowth<br />
  3. 3. Agenda<br />Overview of List Components <br />DataGrid and AdvancedDataGrid<br />Why should we take care of them<br />ItemRenderers<br />Building Slim ItemRenderers<br />Tips and Guidelines<br />Questions<br />
  4. 4. Get To It<br />Focus will be looking at best practices for dealing with custom cell formatting<br />Data customization in DataGrid and AdvancedDataGrid<br />Many of the concepts can be used in the other List components<br />
  5. 5. The Interwebs<br />The Internet is full of examples about how to use Flex components.<br />Some are great<br />Some are ok<br />Others, let’s pretend they don’t exist.<br />
  6. 6. Out Of The Box<br />Flex 3 provides several components for presenting data in a list format:<br />List Controls <br />List <br />Tree<br />DataGrid<br />TileList<br />Menu<br />And More…<br /><ul><li>Data Visualization</li></ul>AdvancedDataGrid<br />OLAPDataGrid<br />
  7. 7. General Features<br />Support Multiple Data Types<br />Drag and Drop<br />Scrolling - Vertical and Horizontal<br />Cell Editing<br />Variable Row Height<br />labelFunction<br />And more...<br />
  8. 8. DataGrid: What Is It?<br />Presents data in a Table format<br />Rows<br />Columns<br />Can automatically create rows & columns based on the data<br />Single Column Sorting<br />Column Reordering<br />
  9. 9. AdvancedDataGrid<br />Supports all the functionality of DataGrid<br />Provides support for Hierarchical Data<br />Understands how to display parent/child relationships.<br />XML, XMLList, HierarchicalData, HierarchicalCollectionView<br />Custom objects with “parent” and “children” properties<br />Advanced Sorting (Multiple Columns)<br />Column Grouping<br />
  10. 10. In Short They…<br />Are a view for the data model<br />Can render data multiple ways<br />Flat, Hierarchical Data, Grouped<br />Are a control that render other controls<br />Headers<br />Renderers<br />Editors<br />ScrollBars, Lines & Other UI Stuff<br />
  11. 11. Why should we take care of it?<br />Performance<br />Troubleshooting<br />Flexibility<br />Maintainability<br />
  12. 12. It Takes Work<br />Large quantities of information<br />Each cell is a component<br />The more rows and columns displayed decreases performance<br />
  13. 13. What Could Go Wrong?<br />Cells appear slow to display<br />Content placed incorrectly “sometimes work, sometimes not work”<br />Content shift a few pixels for no reason<br />Scrolling is jumpy or lag<br />Sorting & Column reordering take a long time to process<br />In worst case, it crashes.<br />
  14. 14. It All Boils Down To<br />Unexpected Results<br />Poor User Experience<br />Cranky Client <br />Your Personal Health: Stress<br />
  15. 15. The Fat : ItemRenderers<br />What are they?<br />Purpose:<br />Read data<br />Present the data (Text, Icons, Controls, etc.)<br />What are they not?<br />Things that compute data to display<br />mx.containers.* (HBox, Canvas, etc.)<br />
  16. 16. ItemRenderer Lifecycle<br />In general, list components will only create as many ItemRenderers as needed to display<br />1 Column X 10 Visible Rows = 10 Renderers<br />100 data objects = 10 Renderers<br />Plus one or two extra for performance reasons<br />ItemRenderers are Recycled<br />
  17. 17. The Default: It’s Text!<br />DataGrid<br />DataGridItemRenderer<br />Extends UITextField > FlexTextField > TextField<br />AdvancedDataGrid<br />AdvancedDataGridItemRenderer<br />Extends UITextField > FlexTextField > TextFIeld<br />
  18. 18. Why Is It Text?<br />Extremely lightweight<br />Direct and to the point<br />Take the least amount of time to create and display<br />No container overhead <br />
  19. 19. But Containers Are Easy…<br />Containers provide a lot of useful functionality:<br />Automatic Layout: Horizontal & Vertical<br />Absolute Layout: Coordinates X and Y<br />Scrollbars<br />Dividers, Tabs, etc.<br />
  20. 20. Too Much Functionality<br />Containers are performance heavy<br />Everything that makes them easy, slows them down<br />10 Rows + 10 Columns = 100 Containers <br />
  21. 21. Custom ItemRenderers<br />Depending on the project requirements, it most likely require a custom ItemRenderer<br />Different text colors based on the data<br />Support for icons<br />Support for other Controls<br />CheckBox, ComboBox, etc.<br />
  22. 22. Do you need one?<br />If you do not need one, do not create one<br />Custom String Manipulation<br />Use a label function if possible<br />Can be done with out creating a renderer<br />
  23. 23. Typical Label Function<br />public function myLabelFunction(item:Object,column:DataGridColumn):String<br />{<br /> return item.firstName + " " + item.lastName;<br />}<br /><mx:DataGrid dataProvider="{myDataProvider}"><br /> <mx:columns><br /> <mx:DataGridColumn labelFunction=“myLabelFunction"/><br /> </mx:columns><br /></mx:DataGrid><br />
  24. 24. That doesn’t cut it<br />A single question is the determining factor for the approach of a ItemRenderer.<br />Q: Does the content require something other than text or a label function can provide?<br />A) No, formatting, custom styling, truncated text<br />B) Yes, I need some icons or checkbox<br />
  25. 25. Just some formatting…<br />Extend the Base ItemRenderer Class for the component<br />AdvancedDataGridItemRenderer<br />DataGridItemRenderer<br />Etc.<br />They extend UITextField<br />Override validateProperties();<br />
  26. 26. ValidateProperties()<br />The part of DataGridItemRender that:<br />Sets the Text property on the TextField<br />Sets the Tooltip<br />Applies WordWrap based on Column settings<br />Apply any necessary formatting based on the data here<br />
  27. 27. Unhealthy Text Renderer<br /><mx:AdvancedDataGridColumn headerText=“Add User"><br /><mx:itemRenderer><br /> <mx:Component><br /> <mx:HBox width="100%" height="100%"><br /> <mx:Label id=“userLabel” text="{}“ <br /> styleName="{(( == 'Jack') ? 0x990000 : 0x000000)}”/><br /> <mx:Image source=“{data.imageURL}” /><br /> </mx:HBox><br /> </mx:Component><br /></mx:itemRenderer><br /></mx:AdvancedDataGridColumn><br />
  28. 28. What is wrong with it?<br />Improper use of a Container<br />Unknown length of the user name<br />ScrollBars<br />Inline ItemRenders are unable to be reused elsewhere in the application<br />
  29. 29. Healthy Text Renderer<br />public class ExpiredUserItemRenderer extends AdvancedDataGridItemRenderer<br />{<br />override public function validateProperties():void<br />{<br /> super.validateProperties();<br />if (data && listData)<br /> {<br /> text = listData.label;<br /> if((data is Person) && (data as Person).isExpired == true)<br /> {<br /> setStyle("color", "0x990000");<br /> toolTip = “Warning! “ + listData.label;<br /> }<br /> else <br /> {<br /> setStyle("color", "0x000000");<br /> toolTip = listData.label;<br /> }<br /> }<br />}<br />}<br />
  30. 30. Why Is It Healthy?<br />It is still just a TextField<br />Does the least amount of work to present the custom text<br />No additional overhead from Container classes or UIComponent<br />
  31. 31. Rendering Other Controls<br />When rendering images or multiple controls:<br />Extend UIComponent<br />Implement Interfaces<br />IDataRenderer<br />IListItemRenderer<br />IDropInListItemRenderer (Optional)<br />Build Custom Functionality<br />
  32. 32. Interfaces Part 1<br />IDataRenderer<br />data (value:Object)<br />Provides the data object for the entire row<br />
  33. 33. Interfaces Part 2<br />IListItemRenderer<br />All renderers must implement this interface<br />Does not define any new methods<br />Extends several other Flex Interfaces<br />UIComponent already has required properties and methods<br />
  34. 34. Interfaces Part 3<br />IDropInListItemRenderer (Optional)<br />listData (value:BaseListData)<br />Provides additional information to the renderer: Column Index, Row Index, dataField<br />Allows the renderer to be re-used with different data fields and List components<br />
  35. 35. Custom Functionality<br />Since we are extending UIComponent, we have the Flex Component Life Cycle<br />createChildren()<br />commitProperties()<br />measure()<br />updateDipslayList(…)<br />
  36. 36. Unhealthy Renderer<br /><?xml version="1.0" encoding="utf-8"?><br /><mx:VBox xmlns:mx=""><br /><mx:Script><br /><![CDATA[<br />protected function linkbutton_clickHandler(event:MouseEvent):void<br />{<br /> // navigate to data.url<br />}<br />]]><br /></mx:Script><br /> <mx:HBox><br /> <mx:Label id="city" text="City: {}" /><br /> <mx:Label id="state" text="State: {data.state}“ /><br /> </mx:HBox><br /> <mx:LinkButton label="More Information“ click="linkbutton_clickHandler(event)"/><br /></mx:VBox><br />
  37. 37. Another Unhealthy Renderer<br />override protected function commitProperties():void {<br /> if(dataChanged) {<br /> // start over<br /> removeChild(pdfIcon);<br /> removeChild(labelField);<br /> }<br />}<br />override protected function updateDisplayList( … ):void {<br /> super.updateDisplayList(unscaledWidth, unscaledHeight);<br />if(data && !pdfIcon) {<br />createPDFIcon();<br />}<br />if(data && !labelField) {<br /> createLabelField();<br />}<br />// position & sizing logic<br />…<br />
  38. 38. What is wrong with it?<br />Improper use of the display list<br />Using removeChild() & addChild() every time the data changes when unnecessary<br />If you know what you need, create it once and update it when the data changes<br />
  39. 39. Healthy Version<br />override protected function commitProperties():void {<br /> if(dataChanged) {<br /> // update the text on the label<br /> if(data) {<br />labelField.text = data.labelField;<br /> labelField.visible = true;<br /> } else {<br />labelField.text = “”;<br /> labelField.visible = false; }<br /> }<br />}<br />
  40. 40. Healthy Component Renderer<br />Example of a Text & Icon Renderer<br />
  41. 41. Tips for Healthy ItemRenderers<br />Avoid extending or containing anything in the mx.containers.* package.<br />Using a Repeater<br />Using Remote Objects! Don’t Do it!<br />Inappropriate use of the display list.<br /><ul><li>addChild(), removeChild(), etc.</li></ul>Excessive recursion in the UIComponent lifecycle.<br />Directly modifying the data model, remember it’s a view<br />
  42. 42. Guidelines<br />When displaying:<br />Text: Extend base ItemRenderer component<br />Images & Controls: Extend UIComponent<br />Add items to the display list once.<br />Avoid removing items from the display list unless necessary<br />
  43. 43. Summary<br />Know the issues related to a poorly performing DataGrid<br />Ask the right question before creating a custom ItemRenderer<br />Base ItemRenderer classes, UITextField and UIComponent are your friends<br />Don’t be afraid to get in there<br />
  44. 44. Questions?<br />
  45. 45. Thank You<br />Ben Schmidtke III<br />Consultant - Digital Primates IT Consulting Group<br /><br />
  46. 46. Bonus Slides <br />
  47. 47. Performance Note<br />A majority of all performance issues with AdvancedDataGrid are related to improper use of a custom item renderer.<br />Even if when updating the dataProvider collection more than necessary, a single poorly made item renderer can decrease performance severely. <br />
  48. 48. The DataProvider<br />Will accept pretty much anything<br />override public function set dataProvider (value:Object):void<br />Behind the scenes if it does not meet certain criteria, it becomes something else. <br />
  49. 49. The DataProvider<br />All data is or becomes one of two types:<br />ICollectionView<br />ArrayCollection<br />XMLListCollection<br />IHierarchicalCollectionView<br />HierarchicalCollectionView<br />
  50. 50. Behind The Scenes<br />if (value is Array) {<br /> collection = new ArrayCollection(value as Array);<br />} else if (value is XMLList) {<br /> collection = new XMLListCollection(value as XMLList); <br />} <br />...<br />else {<br />// convert it to an array containing this one item<br />var tmp:Array = [];<br />if (value != null)<br /> tmp.push(value);<br /> collection = new ArrayCollection(tmp);<br /> }<br />
  51. 51. CollectionEvent<br />collection.addEventListener(<br /> CollectionEvent.COLLECTION_CHANGE, …);<br />AdvancedDataGrid watches for CollectionEvent to respond accordingly keeping things up to date.<br />HierarchicalCollectionView Caches parent/child relationships for quick lookups and respond to the parent & children properties changing.<br />
  52. 52. Issue 1: CollectionEvent<br />Every time a collection event is dispatched on the dataProvider, AdvancedDataGrid may perform a considerable amount of work including:<br />Rebuilding the data view<br />Reconstructing Hierarchical Structures & Updating Cached Collections if necessary<br />Setting the data on all visible renderers<br />
  53. 53. DataProvider Guidelines<br />Manage your data prior setting the dataProvider<br />ArrayCollection, XMLListCollection or HierarchicalCollection<br />Apply updates to data objects in bulk if possible<br />Example: When editing a property, set the value once not one character at a time.<br />