Archive for the 'Best Practices' Category

23
Jul

Reduce complexity from the DisplayList and increase performance

One of the easiest approaches to increase performance in Flash app is to remove any hidden objects from the Flash display list, and use the minimum amount of display objects. The code execution goes through the display list from the top layer, the Stage, and through the main Application class. Flash Player executes code and renders all the children in the display list from top to button until it reaches the display object. A container can be anything that extends the DisplayObjectContainer such as UIComponent, Group or a Sprite.

displaylisttree

Especially with MXML, it’s very easy to nest display objects, however it’s VERY expensive every time we nest display objects, since each display object added to the display list is extending a class that extends a class etc. To understand why it is so expensive to nest. Let’s take a look at the display list class hierarchy.

display_list

ActionScript 3

When it comes to the Display list, up to ActionScript 3 all display objects used to be MovieClip. MovieClip class is the core class for animation in Flash Professional and early version of Flash (AS 1 & AS 2). Each movie clip symbol includes behaviors and functionality of display objects, as well as the additional properties for controlling the timeline. There are many cases where you don’t need that extra layer and overhead of the timeline and in fact AS3 introduced a new objects call DisplayObject. DisplayObject is the low level base class for all objects that can be placed on the display list it extends EventDispatcher (which is based on an object). It includes classes to help manage the object such as cacheAsBitmap and visual properties.

Display object containers are types of display objects that can also include child objects that are display objects. The DisplayObjectContainer includes methods to handle managing the children such as addChild, numChildren and removeChild.

There are times where you need to display graphics but don’t need a timeline. That’s when you rather use a Sprite, which extends DisplayObjectContainer. As general rule of thumb — you rather use DisplayObject classes or classes that are subclasses such as Bitmap, Shape or Sprite over a MovieClip.

Flex 3

Next is Flex being thrown into the mix. Flex core class for the display objects is the FlexSprite class, which is nothing more Then a Sprite with the ability to returns a string indicating the location of this object. Then comes UIComponent which extends FlexSprite and is the base class for every visual component in Flex 3. UIComponent includes keyboard and mouse interactions, but also allow disabling these interactions for objects that don’t need that — such as labels. It also includes many features such as accessibility, Styles, States, Invalidation & Validation, Databinding, Effects, Embedding fonts and much much more.

Flex 4

Next is Flex 4. Flex 4 is using a Group as the base container class for visual elements in Spark (just like UIComponent for MX). Then you have a list of component that can be used such as Skin, Graphic, HGroup and VGroup.

In addition to Group you have the SkinnableComponent, which is the super class for all Spark components, it defines the base class for skinnable components. The skins used by a SkinnableComponent class are typically children classes of the Skin class.

For instance, take the Spark Button component as an example. The ButtonBase class is the base class for the all Spark button components. The Button and ToggleButtonBase classes are subclasses of ButtonBase. Similarly, looking at other component such as CheckBox and RadioButton classes there are subclasses of ToggleButtonBase. The Button component then extends the ButtonBase class and uses the default skin, which includes a text label. You can then define a custom skin class to add an image to the control or anything else you need. The default button skin is spark.skins.spark.ButtonSkin, which extends Skin. What we end up in Spark are components that can be easily skin and changed, however they are heavier.

So let’s do some testing. In term of memory usage of display objects:


Shape: 224 bytes
Sprite: 392 bytes
MovieClip: 428 bytes
UIComponent: 1036 bytes
Group: 1200 bytes

Next, let’s test to see the Flash Player code execution time on a frame. I will be using the FrameStats tool I created few days ago. What I have done is created a quick test harness and added the method to the FrameStats tool. It allows you to see information in regards to the code execution time in Milliseconds for a frame or few frames. I will be dropping the framerate to 1 second (so it’s more clear to test and watch the results) and Then pass a method that will be added to display object and add display objects to the display list. Then we can track the frame life cycle in the console.


			protected function creationCompleteHandler():void
			{
				frameStats = new FrameStats(FlexGlobals.topLevelApplication, false );
				frameRateControl = new FrameRateControl( FlexGlobals.topLevelApplication, false, false, 1, 1);

				var componenent:UIComponent = new UIComponent();
				componenent.addChild( frameStats );
				frameStatsHolder.addElement( componenent );

				trace( "Sprite: " + getSize(new Group()) );	

				uicom.addChild( sprite );
				frameStats.testingExecutionTimeOfMethod( methodToTest, 10000 );
			}

			private function methodToTest():void
			{
				sprite.addChild( new Group() );
			}

		]]>
	</fx:Script>

	<s:Group id="frameStatsHolder" />
	<mx:UIComponent id="uicom" />

Display Objects
When adding 10,000 display objects I am getting the following for the main base classes constructor code execution and their childern:


Shape
Constructor code of children executed: 276

Sprite
Constructor code of children executed: 399

UIComponent
Constructor code of children executed: 1078

Group
Constructor code of children executed: 1195

As expected, the execution of the constructor code and each child constructor code takes longer when the class has many nested objects. It good to know that the Flash Player usually turn methods into native code except for the constructor, so the execution time takes longer on constructor than other classes and we should keep constructors with the least amount of code possible.

Adding 1,000 display objects

Button

Although, I added 10,000 display objects SimpleButton it took only 33 milliseconds on a 1 fps Player framerate the reason is that SimpleButton is low level and nest at the same tree level as DisplayObject. Spark Button takes much longer to go through the constructor code than Halo — however, interesting to see that Spark Button uses less execution time to render on the display list.


SimpleButton
Constructor code of children executed: 33
Final user code executed: 730
Player renders changes display list: 304

mx.Button
Constructor code of children executed: 820
Player renders changes display list: 7075

s:Button
Constructor code of children executed: 2392
Player renders changes display list: 4539

Text

Adding text has interesting results as well. Spark Label did very well in term of rendering but still can’t beat Halo components in term of constructor time. TLF did very poorly on rendering (as expected) but decent on the constructor code.


TextField
Constructor code of children executed: 68
Player renders changes display list: 168

mx:Text
Constructor code of children executed: 743
Player renders changes display list: 685

S:Label
Constructor code of children executed: 1136
Player renders changes display list: 198

s:RichText
Constructor code of children executed: 416
Player renders changes display list: 3224

Conclusion

  • Use low level classes such as TextField, SimpleButton (when possible) over halo and Spark. It will require more coding but will improve performance.
  • Avoid using TLF
  • Use Halo components over Spark components.
  • When creating custom components use Sprite over MovieClip and UIComponent over Group
  • When creating vector graphics it’s recommended to use Shape display object.
15
Apr

Flex data binding pitfalls: common misuses and mistakes - article on Adobe Developer Connection

My article about Data Binding is up on Adobe Developer Connection. Data binding is one of the most used and useful features when building Flex and Adobe AIR applications. At the same time, however, data binding can slow application initialization and cause frustration when developers don’t fully understand how the mechanism works. It is a good idea to make sure you are using it correctly and only when needed. In this article, I’ve compiled a list of ten common pitfalls and mistakes that developers are susceptible to when building an application that uses data binding.

Read the article here:

Flex data binding pitfalls: common misuses and mistakes

screen-shot-2010-04-14-at-111857-pm

Cheers :)

05
Nov

Object pooling in Flex / ActionSctipt

Back in March of 2008 I published an object pooling utility class that allow you to place objects into a collection and use them when needed. That class came handy on a recent project where I had to use few instances of DataGrid, which is known to be one of the most expensive components in Flex which many believe should be avoided at all cost. The app I built had to create instances of data grid during runtime and than remove them from the display object. Object pooling is a great design pattern to handle these cases where you need to use the same object over again and again.

The reason is that object creation takes much resources and should be avoided in cases where you need the object often. I looked over the class and although I wrote it in 2008 it is still in good shape. One thing I noticed is that it was using an ArrayCollection. I have upgraded the class to use a Dictionary instead of ArrayCollection using a HashCollection utility class I developed which is using the Dictionary with a weak reference.

Download and look at the ReusablePool utility class:
http://code.google.com/p/eladlib/source/browse/trunk/EladLibFlex/src/com/elad/framework/objectpoolmanager/ReusablePool.as

To implement the class and show you an example I will be using an application that uses three objects: video, image and a list component. When you add the element to the application and then remove it and keep adding these objects agains and again you put a memory expense and you can see a small hickup. However, when you are using Object pool you keep the memory usage low since the objects are cached and you save on the object instantiation cost. As you can see the application is running smoothly while adding and removing objects from the display.

The complete implementation code can be seen below:


<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/halo"
			   minWidth="1024" minHeight="768"
			   creationComplete="setObjects()"
			   viewSourceURL="srcview/index.html">	

     <fx:Script>
          <![CDATA[
               import com.elad.framework.objectpoolmanager.Reusable;
               import com.elad.framework.objectpoolmanager.ReusablePool;

               import mx.collections.ArrayCollection;
               import mx.containers.Canvas;
               import mx.controls.Image;
               import mx.controls.VideoDisplay;
               import mx.core.UIComponent;

               import net.hires.debug.Stats;

               private var reusablePool:ReusablePool = ReusablePool.getInstance();
               private var canvas:Canvas = new Canvas;

               private function setObjects():void
               {
                    // adding stats
                    component.addChild( new Stats() );
                    addElement(component);                         

                    // adding the object to the collection
                    reusablePool.setReusable( new Reusable(createUI(), "FlexImage") );

                    // adding an array object
                    reusablePool.setReusable( new Reusable(createArray(), "arrayList") );

                    // adding video UI object
                    reusablePool.setReusable( new Reusable(createVideoUI(), "videoUI") );                                                            

                    this.addElement(canvas);
               }

               private function useUIObject(name:String):void
               {
                    // getting the collection
                    var reusable:Reusable = reusablePool.acquireReusable(name);
                    var component:UIComponent = reusable.object as UIComponent;

                    // use the object
                    canvas.removeAllChildren();
                    canvas.addElement(component);

                    // return collection back to the pool of objects
                    reusablePool.releaseReusable(reusable);
               }

               private function useArrayObject():void
               {
                    // getting the collection
                    var reusable:Reusable = reusablePool.acquireReusable("arrayList");
                    var dp:ArrayCollection = reusable.object as ArrayCollection;

                    list.dataProvider = dp;

                    // return collection back to the pool of objects
                    reusablePool.releaseReusable(reusable);
               }

               private function noCacheArrayObject():void
               {
                    var dp:ArrayCollection = createArray();
                    list.dataProvider = dp;
               }

               private function noCacheUIObject():void
               {
                    canvas.removeAllChildren();
                    canvas.addElement(createUI());
               }

               private function noCacheVideoUIObject():void
               {
                    canvas.removeAllChildren();
                    canvas.addElement(createVideoUI());
               }     

               private function createUI():UIComponent
               {
                    var image : Image = new Image();
                    image.source = "http://blog.digitalbackcountry.com/wp-content/uploads/flash_builder_logo.png";
                    image.width = 400;
                    image.height = 300;
                    image.x=10;
                    image.y=300;                    

                    return image;
               }

               private function createVideoUI():UIComponent
               {
                    var videoDisplay:VideoDisplay = new VideoDisplay();
                    videoDisplay.source = "http://kakonacl.dip.jp/PlayerTry/TestMovies/FLV/FLV4/Flash.flv";
                    videoDisplay.x = 10;
                    videoDisplay.y = 300;
                    videoDisplay.width = 300;
                    videoDisplay.height = 300;

                    return videoDisplay;
               }

               private function createArray():ArrayCollection
               {
                    var array:ArrayCollection = new ArrayCollection();

                    for (var i:int=0; i<10000; i++)
                    {
                         array.addItem({label: i});
                    }

                    return array;
               }               

          ]]>
     </fx:Script>

     <s:Label x="10" y="10"
                text="These examples shows memory usage with using the object pooling collection and without it."
                fontWeight="bold" height="33"/>

     <s:Label x="10" y="61"
                text="Cached Object Pooling" width="200" fontWeight="bold"/>

     <s:Button x="10" y="87"
                 label="UIobject"
                 click="useUIObject('FlexImage');" width="200"/>

     <s:Button x="10" y="117"
                 label="array"
                 click="useArrayObject();" width="200"/>                  

     <s:Button x="10" y="147"
                 label="Video UI"
                 click="useUIObject('videoUI');" width="200"/>

     <s:List id="list"
               x="325" y="79"
               width="126" height="200" />

     <s:Label x="10" y="178"
                text="Regular objects" width="200" fontWeight="bold"/>

     <s:Button x="10" y="202"
                 label="UIobject"
                 click="noCacheUIObject();" width="200"/>

     <s:Button x="10" y="232"
                 label="Array"
                 click="noCacheArrayObject()" width="200"/>          

     <s:Button x="10" y="262"
                 label="Video UI"
                 click="noCacheVideoUIObject()" width="200"/>

     <mx:UIComponent id="component" x="237" y="83" width="70" height="100"/>     

</s:Application>

screen-shot-2009-11-05-at-104133-pm

To measure the memory usage you can use the small statistic class that was developed by Mr.doob. Additionally, you can take a look at the Eclipse Profiler. In first scenario where I add an element to the application and remove it, the profiler shows as if we have a memory leak since the usage peaked to the “red” lines. I am not saying this is a memory leak, but I am pointing out that the memory usage is high since the objects were removed but haven’t been picked up by the GC yet. As you know using the removeAllChildren() remove the object from the component but is not necessarily ensure the GC will come and release the memory right away. See Profiler screen shot below:

screen-shot-2009-11-05-at-105952-pm

In the second scenario, the objects are cached and I am not putting any memory constrains on my application. See figure below.

screen-shot-2009-11-05-at-110137-pm

The utility class can be limited to the amount of objects you want to store, plus you can tie the class to a logic that will clear all the objects when needed.

Let’s take a look at the code to create an instance of the utility class and add an object.

The utility class is a singleton so we can use the same object through the life cycle of the application.


private var reusablePool:ReusablePool = ReusablePool.getInstance();

To add an object you create a Reusable object that holds the object and the name of the object:


// adding the object to the collection
reusablePool.setReusable( new Reusable(createUI(), "FlexImage") );

When you are ready to retrieve the object use the acquireReusable method, which will remove the object from the object collection:


// getting the collection
var reusable:Reusable = reusablePool.acquireReusable(name);
var component:UIComponent = reusable.object as UIComponent;

When you are done and want to send the object back to the object pool collection use:


reusablePool.releaseReusable(reusable);

Cheers :)

29
Dec

TDD and Asynchronous Tests with Cairngorm applications

Model-View-Controller (MVC) frameworks such as PureMVC or Cairngorm and TDD makes a good marriage. MVC framework works very well with TDD since the application logic is separated from the front view and the data. TDD allows us to create Test Cases on the logic only, as well as create a test case for the presentation layer.

With that said, Cairngorm by default doesn’t separate the view, behavior and model in each container. In order to utilize TDD it’s recommended to use the Presentation model pattern. Few blogs back I covered Cairngorm and the presentation model so in this blog post I am going to continue by showing you how to use TDD and FlexUnit to test your user stories.

The application I am using is simple application with only three business rules:

1. Connect to adobe feeds and retrieve the latest feeds related to Flex.
2. Display these results in a list.
3. Upon user clicking an item on the list display detail information.

Take a look and download the source code:
CairngormPM and TDD

So far you can easily figure out how to create the User Story for item #1, To test Asynchronous tests in FlexUnit we can use the “addAsync” method. Here’s an example of calling the Flex News feeds.


package flexUnitTests
{
    import flexunit.framework.TestCase;

    import mx.rpc.events.ResultEvent;
    import mx.rpc.http.HTTPService;

    public class ServiceTestCase extends TestCase
    {
        private var service:HTTPService;

        public function ServiceTestCase(methodName:String=null)
        {
            super(methodName);
        }

        override public function setUp():void
        {
            service = new HTTPService();
            service.url = "http://rss.adobe.com/en/resources_flex.rss";
            service.resultFormat = "e4x";
        }

        override public function tearDown():void
        {
            service = null;
        }

        public function testServiceCall():void
        {
            service.addEventListener(ResultEvent.RESULT, addAsync(serviceResultEventHandler, 2000, {expectedResults: "Flex News"}, failFunction));
            service.send();
        }

        private function serviceResultEventHandler(event:ResultEvent, data:Object):void
        {
            var val:String = event.result[0].channel.title;
            assertTrue("Unable to retrieve Flex News feeds", val, data.expectedResults);
        }

        private function failFunction(data:Object):void
        {
            fail("Unable to connect to Flex News feeds");
        }
    }
}

Essentially, we should create a test case for each Cairngorm user gesture. So the process is as follow:

1. Understand what the purpose of the user gesture and what model get effected
2. Dispatch the event and watch changes in the model.

Additionally, it’s recommended to create FlexMonkey view tests to ensure the application view is changing according to our requirement and will test the container.

I am not going to explain the entire code, let me cover one test case and you can figure out the rest;

The ReadAdobeFeedsTestCase this test case is based on testing ReadAdobeFeedsEvent. Each Cairngorm Event-Command is based on a user gesture and you need to understand what that user gesture means.

In our case we dispatch the event and on result we place the collection in the model, so we can dispatch the event and make sure the results reaches the model. Here’s the watcher:


watcherInstance = ChangeWatcher.watch(modelLocator.feedsPanelViewerPM,["feedsCollection"],
addAsync(itemsChanged, 2000, {compareResults: 0}, failFunc));
new ReadAdobeFeedsEvent().dispatch();

And once a change is made to the model the binding method will dispatch an event automatically and we can listen to that change and compare the result in the model:


private function itemsChanged(event:Event, data:Object):void
        {
            var len:int = modelLocator.feedsPanelViewerPM.feedsCollection.collection.length;
            Assert.assertTrue("Collection is empty", len>data.compareResults);
        }

Take a look at the complete code:


package flexUnitTests.events
{
    import com.elad.application.events.ReadAdobeFeedsEvent;
    import com.elad.application.model.ModelLocator;

    import flash.events.Event;

    import flexunit.framework.Assert;
    import flexunit.framework.TestCase;

    import mx.binding.utils.ChangeWatcher;

    public class ReadAdobeFeedsTestCase extends TestCase
    {

        [Bindable]
        private var modelLocator:ModelLocator = ModelLocator.getInstance();    

        private var watcherInstance:ChangeWatcher;    

        public function ReadAdobeFeedsTestCase(methodName:String=null)
        {
            super(methodName);
        }

        public function testReadAdobeFeedsEvent():void
        {
            watcherInstance = ChangeWatcher.watch(modelLocator.feedsPanelViewerPM,["feedsCollection"],
                addAsync(itemsChanged, 2000, {compareResults: 0}, failFunc));

            new ReadAdobeFeedsEvent().dispatch();
        }

        private function itemsChanged(event:Event, data:Object):void
        {
            var len:int = modelLocator.feedsPanelViewerPM.feedsCollection.collection.length;
            Assert.assertTrue("Collection is empty", len>data.compareResults);
        }

        private function failFunc(data:Object):void
        {
            fail("Couldn't connect to Adobe feeds and update application model");
        }
    }
}

We have to make some changes in the TestRunner.mxml container.
The reason is that we need to add the same references as we added in our main application to the singleton classes: Front Controller and Service Locator. Otherwise the application will not be able to map between the event and commands as well as lack the ability to make service calls.


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:flexunit="flexunit.flexui.*"
	xmlns:business="com.elad.application.business.*"
	xmlns:control="com.elad.application.control.*"
	creationComplete="onCreationComplete()">

	<mx:Script>
		<![CDATA[
			import flexUnitTests.GesturesTestSuite;

			import flexUnitTests.events.ReadAdobeFeedsTestCase;
			import flexUnitTests.events.UserSelectedFeedTestCase;
			import flexunit.framework.TestSuite;

			private function onCreationComplete():void
			{
				testRunner.test = currentRunTestSuite();
				testRunner.startTest();
			}

			public function currentRunTestSuite():TestSuite
			{
				var testsToRun:TestSuite = new TestSuite();

				testsToRun.addTest(GesturesTestSuite.suite());
				testsToRun.addTest(new UserSelectedFeedTestCase("testUserSelectedFeedEvent"));
				testsToRun.addTest(new ReadAdobeFeedsTestCase("testReadAdobeFeedsEvent"));
				return testsToRun;
			}			

		]]>
	</mx:Script>

	<control:testController />
	<business:Services />
	<flexunit:TestRunnerBase id="testRunner"/>

</mx:Application>

download the source code

I will published a post soon on creating Test Suites and Test Cases for PureMVC, which is much easier than Cairngorm applications since the presentation containers are already split from the data and logic.

04
Dec

Best practices for mapping binary objects from service calls

Working with Remote Object Service invocation utilizing binary connection such as AMFPHP or others, it is often challenging to map the server data with the client data, even when the object is identical in terms of object properties. When you try to cast the object you get a null VO. The reason is that the run-time compiler is unable to cast the object to the VO type.

I was surprised to see experienced Flex developers manually mapping objects directly or creating constructors to the VO to map every single property. Here’s what we shouldn’t do:


var result:ResultEvent = data as ResultEvent;
var user:UserVO = new UserVO();

user.fname = result.result[0].fname;
user.lname = result.result[0].lname;
user.email = result.result[0].email;
etc...

The reason we don’t want to do that, is that this type of approach can work well on a simple VO, however when we have a complex VO with many properties, the code starts to look unprofessional.

I think that as engineers many times we are not sure what’s the best approach/practices, but we can certainly identify wrong approaches. For instance, when we find ourselves doing copy pasting we certainty should find a new approach or if there is no approach available, we can develop our own tool/API to handle the use case.

The right approach is to declare a static method that takes a VO object of type “*” since we don’t know the VO type. Iterate through the collection and map the properties and than return the VO back. Here’s a small utility to handle the mapping:


/*

 Copyright (c) 2008 Elrom LLC. All Rights Reserved 

 @author   Elad Elrom
 @contact  elad.ny@gmail.com

 @internal 

 */
package com.elad.framework.utils
{
	public final class VOHelper
	{
		/**
		 * Method to mpa an object to a VO type.  The are cases where the object returned from the service cannot
		 * cast as the type of VO, this static method will allow you map the VO.
		 *
		 * @example: var user:UserVO = VOHelper.ConvertObjecToVO(result.result[0], new UserVO() );
		 *
		 * @param ob	the object returned from the server.
		 * @return	return the VO object.  Since we want to use many types of VO we use * to generate it dynamically.
		 *
		 */
		public static function ConvertObjecToVO(ob:Object, vo:*):*
		{

			for(var parameter:String in ob)
			{
				try
				{
					vo[ parameter.toLowerCase() ] = ob[ parameter ];
				}
				catch( err:Error )
				{
				}
			}

			return vo;
		}
	}
}

Now you can just use the utility to map the object;


var user:UserVO = VOHelper.ConvertObjecToVO(result.result[0], new UserVO() );