Archive for the 'Flex' Category



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 :)

30
Mar

Improve Flash Catalyst Performance

@polyGeek reminded me today (see blog post here) about increasing the memory size allocated to Eclipse and made me wonder if I can do the same thing to FlashCatalyst.

You probably noticed that Flash Catalyst is often slow. As you may know Flash Catalyst is based on Eclipse IDE and just like any Eclipse instance you can improve performance simple by tweaking the heap size and permSize to maximize performance. You should give the VM as much ram as you can and set the min and max values (the same) to avoid resizing of your memory.

On PC change “Adobe Flash Catalyst CS5.ini” located here
C:\Program Files\Adobe\Adobe Flash Catalyst CS5

On MAC: Under /Applications/Adobe\ Flash\ Catalyst\ CS5 Adobe Flash Catalyst\ , select Adobe Flash Catalyst CS5.app and right click the app > select “Show Package Contents”, and then traversed to find the location of the “Adobe Flash Catalyst CS5.ini” file.

Flash Catalyst comes with larger memory allocation than Flash Builder, see below:


-clean
-vmargs
-Xdock:icon=../Resources/fc_app.icns
-Xdock:name=Flash Catalyst
-XstartOnFirstThread
-Xms512m
-Xmx512m
-XX:MaxPermSize=256m
-XX:PermSize=64m
-Dorg.eclipse.swt.internal.carbon.smallFonts
-Dorg.eclipse.swt.internal.carbon.noFocusRing

You can increase the Xms and MaxPermSize to improve performance.
I have 4GB RAM on my MBP machine and changed the heap to 1024m and a permSize to 512m.


-Xms1024m
-Xmx1024m
-XX:MaxPermSize=512m

I notice significant improvement. Cheers :)

29
Mar

FXGStringConverter - converts FXG text string to component during runtime

There are times were you need to take an FXG (Flash XML Graphic) from Photoshop, Illustrator or Flash Catalyst and load it during runtime. FXG is usually handled by the MXMLC which turns the declarative language into ActionScript code. The utility class will do just that and convert the text string into ActionScript code which can than be added to the display object or manipulated during runtime. Take a look at a simple implementation which allow the user to insert text string and it will turn it into a group component:


<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/mx"
	minWidth="955" minHeight="600">

	<fx:Script>
		<![CDATA[
			import com.elad.framework.utils.fxgconverter.FXGStringConverter;

			protected function button_clickHandler(event:MouseEvent):void
			{
				var comp:Group = FXGStringConverter.convertFXGStringToComponent( textArea.text, true );
				group.addElement( comp );
			}			

		]]>
	</fx:Script>

	<s:TextArea id="textArea" width="300" height="200" />
	<s:Button id="button" x="14" y="214" label="Submit" click="button_clickHandler(event)"/>
	<s:Group id="group" width="500" height="500" x="0" y="300" />	

</s:Application>

screen-shot-2010-03-30-at-92633-am

Although I tested it on all the code that I needed, keep in mind that the code is still in alpha and is not fully tested, so I am sure there may be cases where it will fail. Also group your FXG code since I haven’t tested it fully with all types of code. See FXG sample below:


<s:Group id="groupSample1">
     <s:Ellipse id="ellipse" width="30" height="30">
          <s:fill>
               <s:SolidColor color="0x000000"></s:SolidColor>
          </s:fill>
      </s:Ellipse>
</s:Group>

The code is published as open source and hosted under my private library:
http://github.com/EladElrom/eladlib

20
Mar

Tip: calculate properties such as position and measurements for Flex Spark Label component

There are cases where you need to find out position and measurements for Flex Spark Label component. There are many cases where you will find the code useful, such in case you need to calculate the width of a text string in pixels during runtime. Take a look at the following code snippet:


var label:Label = new Label();
label.regenerateStyleCache( false );
var textMetrics:TextLineMetrics = label.measureText( name );
var textWidth:int = textMetrics.width;

textWidth will hold the text width in pixels.

TextLineMetrics is part of the TLF framework and contain information about the text position, measurements etc. See more here:
http://livedocs.adobe.com/labs/textlayout/flash/text/TextLineMetrics.html

label.regenerateStyleCache(false); is used to ensure that the label component updated the metrics since many times commit properties or invalidate properties wouldn’t do the trick.

There are cases where you need to truncate (remove text and add dot dot dot) the text of a Spark Label once the text exceed a certain width. To do that you can add the following command:


import spark.components.supportClasses.TextBase;
TextBase.mx_internal::truncationIndicatorResource = "...";

Make sure you also add maxDisplayedLines="1" to the label component.

20
Mar

Tutorial - Drag And Drop an FXG element

One of the most used visual development in Flex is drag and drop functionality I am using Flex 4 SDK since early iteration and really enjoyed the new Spark component and FXG (Flash XML Graphic) architecture. I was asked last week by one of my developer to help him understand how to work with FXG code and apply drag and drop functionality, so I created a quick POC (Proof Of Concept) and decided to share it in case someone have a similar application and running into difficulties. Before we get started I want to point out the the code is written very quickly and can be improved. I only wanted to give the basics and you can take it from here.

Drag and drop operation consists of three steps:

  • Initiation
  • Dragging
  • Dropping

To drag FXG element is similar to how you would create drag and drop in Flex3, since the FXG can be wrapped in a Group which extends GroupBase (which than extends UIComponent), however there are few changes in terms of wrapping the FXG as an object that the DragManager recognize.

Let’s take a look.

We set two components: a List to hold the FXG components and a Group component to hold the drop items, see below:


	<!-- source -->
	<s:List id="list" mouseDown="mouseDownHandler(event)"
			x="0" y="0"
			skinClass="components.DataList"
			width="169" height="200"/>

	<!-- dest -->
	<s:Group id="group"
			 width="200" height="200"
			 x="190" y="0"
			 dragEnter="dragEnterHandler(event);"
			 dragDrop="dragDropHandler(event);">

		<s:Rect top="0" left="0" right="0" bottom="0">
			<s:fill>
				<s:SolidColor color="0xCCCCCC" />
			</s:fill>
		</s:Rect>

	</s:Group>

Once the user click mouse down on an item in the list the event handler start tracking the mouse move event and will call the startDragItem method:


// holds the selected index
private var selectedIndex:int;

public function mouseDownHandler( event:MouseEvent ):void
{
	selectedIndex = (event.currentTarget as List).selectedIndex;
	this.addEventListener(MouseEvent.MOUSE_MOVE, startDragItem );
}

The startDragItem method will pick the item that was selected and cast it as a ComponentVO and set the following:

  • drag source
  • drag initator
  • set the image source
  • set the data

Once we create all that information that is needed you can set the DragManager as follow:
DragManager.doDrag( dragInitiator, dragSource, event, dragProxy );

See code below:


private function startDragItem( event:MouseEvent ):void
{
	var selectedItem:ComponentVO = collection.getItemAt( selectedIndex ) as ComponentVO;

	// drag source
	var dragSource:DragSource = new DragSource();

	// drag initator
	var dragInitiator:Group = selectedItem.fxg;

	// create an image
	var bitmapData:BitmapData = getBitmapData( selectedItem.fxg );
	var bitmap:Bitmap = new Bitmap( bitmapData );

	// set the image source
	var dragProxy:Image = new Image();
	dragProxy.source = bitmap;

	// set the data
	dragSource.addData( selectedItem, "ComponentVO" );

	DragManager.doDrag( dragInitiator, dragSource, event, dragProxy );
}

// retrieve the bitmap data of a component
private function getBitmapData( target:UIComponent ):BitmapData
{
	var bitmapData:BitmapData = new BitmapData( target.width, target.height );
	var matrix:Matrix = new Matrix();
	bitmapData.draw( target, matrix );

	return bitmapData;
}

The destination have event handlers to trace drag enter and drag drop events:
dragEnter=”dragEnterHandler(event);” dragDrop=”dragDropHandler(event);”

The handlers will allow adding the item to the destination component and add the actual FXG component:


// drop item
private function dragDropHandler( event:DragEvent ):void
{
	this.removeEventListener( MouseEvent.MOUSE_MOVE, startDragItem );

	var selectedItem:ComponentVO = event.dragSource.dataForFormat('ComponentVO') as ComponentVO;
	selectedItem.fxg.x = 0;
	selectedItem.fxg.y = 0;
	this.group.addElement( selectedItem.fxg );
}

private function dragEnterHandler( event:DragEvent ):void
{
	var dropTarget:Group = event.currentTarget as Group;

	if (event.dragSource.hasFormat('ComponentVO'))
	{
		DragManager.acceptDragDrop(dropTarget);
	}
}

Last part is to create static FXG component we can use. You can load the object or runtime or pass it from a different class or service, this example is just a POC so I kept it simple but you get the idea. Once the creationCompleteHandler is called the collection will be filled with the two objects:


// handles creation complete
protected function creationCompleteHandler(event:FlexEvent):void
{
	collection = new ArrayCollection();

	collection.addItem( new ComponentVO( "Item1", groupSample1 ) );
	collection.addItem( new ComponentVO( "Item2", groupSample2 ) );

	list.dataProvider = collection;
}

The sample FXG code will look as follow:


	<!-- Holds a sample FXG code -->
	<s:Group id="groupSample1">
		<s:Ellipse width="30" height="30">
			<s:fill>
				<s:SolidColor color="0x000000">
				</s:SolidColor>
			</s:fill>
		</s:Ellipse>
	</s:Group>
	<s:Group id="groupSample2">
		<s:Ellipse width="30" height="30">
			<s:fill>
				<s:SolidColor color="0x00FF00">
				</s:SolidColor>
			</s:fill>
		</s:Ellipse>
	</s:Group>	

Complete code is listed 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/mx"
			   minWidth="955" minHeight="600"
			   creationComplete="creationCompleteHandler(event)">

	<fx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.controls.Image;
			import mx.core.DragSource;
			import mx.core.UIComponent;
			import mx.events.DragEvent;
			import mx.events.FlexEvent;
			import mx.managers.DragManager;

			import vo.ComponentVO;

			// holds the collection
			private var collection:ArrayCollection;

			// holds the selected index
			private var selectedIndex:int;

			public function mouseDownHandler( event:MouseEvent ):void
			{
				selectedIndex = (event.currentTarget as List).selectedIndex;
				this.addEventListener(MouseEvent.MOUSE_MOVE, startDragItem );
			}

			// handles creation complete
			protected function creationCompleteHandler(event:FlexEvent):void
			{
				collection = new ArrayCollection();

				collection.addItem( new ComponentVO( "Item1", groupSample1 ) );
				collection.addItem( new ComponentVO( "Item2", groupSample2 ) );

				list.dataProvider = collection;
			}

			private function startDragItem( event:MouseEvent ):void
			{
				var selectedItem:ComponentVO = collection.getItemAt( selectedIndex ) as ComponentVO;

				// drag source
				var dragSource:DragSource = new DragSource();

				// drag initator
				var dragInitiator:Group = selectedItem.fxg;

				// create an image
				var bitmapData:BitmapData = getBitmapData( selectedItem.fxg );
				var bitmap:Bitmap = new Bitmap( bitmapData );

				// set the image source
				var dragProxy:Image = new Image();
				dragProxy.source = bitmap;

				// set the data
				dragSource.addData( selectedItem, "ComponentVO" );

				DragManager.doDrag( dragInitiator, dragSource, event, dragProxy );
			}

			// retrieve the bitmap data of a component
			private function getBitmapData( target:UIComponent ):BitmapData
			{
				var bitmapData:BitmapData = new BitmapData( target.width, target.height );
				var matrix:Matrix = new Matrix();
				bitmapData.draw( target, matrix );

				return bitmapData;
			}

			// drop item
			private function dragDropHandler( event:DragEvent ):void
			{
				this.removeEventListener( MouseEvent.MOUSE_MOVE, startDragItem );

				var selectedItem:ComponentVO = event.dragSource.dataForFormat('ComponentVO') as ComponentVO;
				selectedItem.fxg.x = 0;
				selectedItem.fxg.y = 0;
				this.group.addElement( selectedItem.fxg );
			}

			private function dragEnterHandler( event:DragEvent ):void
			{
				var dropTarget:Group = event.currentTarget as Group;

				if (event.dragSource.hasFormat('ComponentVO'))
				{
					DragManager.acceptDragDrop(dropTarget);
				}
			}

		]]>
	</fx:Script>

	<!-- Holds a sample FXG code -->
	<s:Group id="groupSample1">
		<s:Ellipse width="30" height="30">
			<s:fill>
				<s:SolidColor color="0x000000">
				</s:SolidColor>
			</s:fill>
		</s:Ellipse>
	</s:Group>
	<s:Group id="groupSample2">
		<s:Ellipse width="30" height="30">
			<s:fill>
				<s:SolidColor color="0x00FF00">
				</s:SolidColor>
			</s:fill>
		</s:Ellipse>
	</s:Group>	

	<!-- source -->
	<s:List id="list" mouseDown="mouseDownHandler(event)"
			x="0" y="0"
			skinClass="components.DataList"
			width="169" height="200"/>

	<!-- dest -->
	<s:Group id="group"
			 width="200" height="200"
			 x="190" y="0"
			 dragEnter="dragEnterHandler(event);"
			 dragDrop="dragDropHandler(event);">

		<s:Rect top="0" left="0" right="0" bottom="0">
			<s:fill>
				<s:SolidColor color="0xCCCCCC" />
			</s:fill>
		</s:Rect>

	</s:Group>

</s:Application>

screen-shot-2010-03-20-at-25531-pm

Download the complete FXP code from here:
http://elromdesign-example-codes.googlecode.com/files/DragDropFXG.fxp

10
Mar

Test Driven Development (TDD) with FlexUnit 4 - Complete Tutorial

After completing my preso at 360|Flex San Jose I realized how many people are having difficulties starting with Test Driven Development (TDD). I had many people walking up to me and telling me about their interest of starting using TDD and how it’s hard to get started. I decided to share my knowledge. This blog entry includes the following:

  • Complete Tutorial building a “real life” application
  • My 360 presentation
  • Complete Project

You can download the doc, preso and project files from here:
http://eladelrom-preso.googlecode.com/files/TDD.zip

The presentation is avaliable below:

Let’s get started.

As Flash applications become more dynamic and complex, they become more difficult to maintain and scale, particularly when business requirements change throughout the course of development. These challenges are significant and they are common in all types of development, including mobile, web, and desktop applications.

For software engineers, this problem is neither new nor confined to a specific platform. Java and ASP developers have been challenged with the same issues and have found Test Driven Development (TDD) a useful technique for creating applications that can be easily maintained.

Luckily, the new version of FlexUnit 4 just got closer in similarity to the JUnit (http://www.junit.org/) project and supports many of the features JUnit has, and more! FlexUnit4 combines features from the previous FlexUnit 1.0 features and Fluint (http://code.google.com/p/fluint/).

FlexUnit 4 allows you can create tests in order to achieve reliability, stability and maintainability of your application, however without proper understanding how to create tests and how to shift your coding style you will not be able to fully take advantage of FlexUnit 4.

The purpose of this wiki page is to give you the tools you need to shift your coding style and start using FlexUnit 4 to the fullest.

Test Driven Development quick overview

That’s exactly where TDD (Test Driven Development) comes in, but what’s TDD anyway? In short, the concept is pretty simple. You write your tests before you write your code. It’s that simple and worth repeating: write tests before code!

Test Driven Development is a software development technique in which programmers are writing a failed test that will define the functionality before writing the actual code.

Furthermore, TDD is about realizing an act of hypocrisy. As software developers our job is to be lazy. We automate repetitive tasks.

Yet the balance of the time spent developing code is actually spent testing and debugging our code manually (80% as some studies suggest). Why would you choose to do this repetitive and annoying task when you automate all of the others?

What it means is that we can let humans do the work they do best while letting computers do the work they do best and ending up with code that is more stable and more maintainable.

The concept of TDD is based on Extreme Programming (XP) development paradigm, which talks about teams that work on the development of dynamic projects with changing requirements and a development cycle that includes TDD for writing the test before the code itself. TDD is not the complete development cycle; it is only part of the Extreme Programming (XP) development paradigm. Preparing the tests before writing the code helps a development team to demonstrate their work in small steps, rather than making the customer or other stakeholders wait for the complete result.

Moving in small increments also makes it easier to accommodate changing requirements and helps ensure that your code does what it needs to do, and nothing more. It is important to mention that the focus of the TDD technique is to produce code and not to create a testing platform. The ability to test is an added benefit.

TDD is based on the idea that anything you build should be tested and if you are unable to test it, you should think twice about whether you really want to build it.

By now, there are many resources that explain how to create simple application, in order to implement TDD, however I yet to find a tutorial that gives a real application so I decided to use a real life example so you can better understand FlexUnit and TDD. While trying to come up with an example I realized that one of my tasks these days is to create an AIR application similar to Adobe MAX Companion AIR Application for a conference I am organizing called: FlashAndTheCity (http://www.flashandthecity). Creating a real application can show you how does the process goes in real development and not in a fake example that tries to make everything simple and easy, since creating applications is complex and change often even as you build your application.

Defining Application’s Objective

Understanding the application objectives is as important as coding your application. Here’s a lessons we can learn from a Master Carpenter: Measure Twice, Cut Once!

You need to understand what you are developing before you get started. In our case, we are building an application that will do the following:

1. Allow attendees to communicate with each other through twitter API.
2. The class will keep a list of tweets with #FlashAndTheCity hashtag
3. The class will check for updates of tweets often

Take a look at the Adobe MAX Companion AIR application (Figure 1), the application we are building is very similar in functionality.

11
Figure 1: Adobe MAX Companion AIR application

In order to understand the problem we need to be able to explain the problem in an everyday language.

User Stories

A good approach to take to ensure the tasks are defined well is to follow Agile software development mythology. The Agile mythologies talks about creating one or more informal sentences in an everyday or business language, this type of approach is known as a User Story. The User Story should be limited in characters and should fit a small paper note card. The user stories are usually written by the client in order to give direction to build the software. Think of this list as your todo list.

In our case here are the User Stories:

1. Retrieve tweets with #FlashAndTheCity HashTag from Twitter API.
2. Have a service call to twitter and retrieve tweets every few seconds.
3. Login into user’s twitter account and retrieve personal information.
4. Store user’s information so user wouldn’t have to login again every time.
5. Post a tweet on twitter from a user
6. Add #FlashAndTheCity Hashtag to a tweet so user wont have to type it every time and the application will be able to retrieve all tweets related to the conference.
7. Keep a list of tweets with the ability to add a tweet & remove a tweet.

Getting started

Creating the application

With the knowledge of what we need to develop we are ready to get started. The first step is to create the application open Eclipse or Flash Builder 4 Beta and create a new project name Companion (see instructions below).

• Select File > New > Flex Project to create the project.
• For the Project Name, type Companion, ensure you set the project as Desktop application type.
• Click Finish.

See figure 2.
2
Figure 2: Create new Flex project for desktop

Creating the class to be tested

The architecture we will follow is creating a utility helper class that will wrap the Twitter API and provide the ability to access the different methods in Twitter API.

Create a new class and call it TwitterHelper based the class on the EventDispacher super class so the utility class will be able to dispatch events when new tweets are available. (I recommend writing the actual class needed after writing the test, however, I wanted to show the two approaches).

3
Figure 3: Create new ActionScript Class

Once you select Finish, the class is created automatically for you, see code below:


package utils
{
     import flash.events.EventDispatcher;
     import flash.events.IEventDispatcher;

     public class TwitterHelper extends EventDispatcher
     {
          public function TwitterHelper(target:IEventDispatcher=null)
          {
               super(target);
          }
     }
}

What important more than deciding if you want to create this class or not is to ensure that the helper class is not implemented, since we need to follow TDD process and write the test before we write the actual code. Our next step is to create the Test Suite and Test case.

Creating your first Test Suite

The next step is to create a test suite.

A test suite is a composite of tests. It runs a collection of test cases. During development you can create a collection of tests packaged into test suite and once you are done, you can run the test suite to ensure your code is still working correctly after changes have been made.

To create a test suite, choose File > New > Test Suite Class (see Figure 4).

4

Figure 4: Creating a new Test Suite Class in Flash Builder 4

After you select New Test Suite Class a wizard window opens up. Fill in the following information:

• In the New Test Suite Class dialog box, name the class CompanionTestSuite.
• Select New FlexUnit 4 Test (see Figure 5).
• Click Finish.

5

Figure 5: Creating a New Test Suite Class named CompanionTestSuite

Note that Although in Extreme Programming you are encouraged to write tests before creating the code (and ideally that’s how you should work), in real life there are many times where you will find yourself writing the tests after the code. Such decisions are made case by case, and it is OK to adjust the methodology to fit your workflow.

Flash Builder 4 added the following class under the flexUnitTests folder:


package flexUnitTests
{
	[Suite]
	[RunWith("org.flexunit.runners.Suite")]
	public class CompanionTestSuite
	{
	}
}

The Suite metadata tag indicates that the class is a suite. The RunWith tag instructs the test runner to execute the tests that follow it using a specific class. FlexUnit 4 is a collection of runners that will run a complete set of tests. You can define each runner to implement a specific interface. You can, for example, specify a different class to run the tests instead of the default runner built into FlexUnit 4.

Add your first test case class

Next, you need to create a test case. A test case comprises the conditions you want to assert to verify a business requirement or a User Story. Each test case in FlexUnit 4 must be connected to a class. To create the class, follow these steps:

Create the Test Case class:

1. Choose File > New > Test Case Class.
2. Select New FlexUnit 4 Test.
3. Type flexUnitTests as the package.
4. Type TwitterHelperTester as the name.
5. Type utils.TwitterHelper as the Class To Test (see Figure 6).

6

Figure 6: Creating a new Test Case class

In case you are creating tests for a class that already existing methods you can select Next and choose the methods you want to test. In our case we are following TDD and creating the test before writing the code so no need to select any methods and you can hit Finish to complete the process and create the Test Case class.

Important: Ensure that there is a reference in CompanionTestSuite.as to TwitterHelperTester:


package flexUnitTests
{
	[Suite]
	[RunWith("org.flexunit.runners.Suite")]
	public class CompanionTestSuite
	{
		public var twitterHelperTester:TwitterHelperTester;
	}
}

You are ready to start writing test code. Open TwitterHelperTester.as and notice that classToTestRef reference has been created automatically for you. Here is the generated code:


package flexUnitTests
{
	import flexunit.framework.Assert;

	import utils.TwitterHelper;

	public class TwitterHelperTester
	{
		// Reference declaration for class to test
		private var classToTestRef : utils.TwitterHelper;

		public function TwitterHelperTester()
		{
		}
	}
}

Implementing your User Stories

Retrieve Tweets User Story

We can start with the first User Story, Retrieve tweets with #FlashAndTheCity HashTag from Twitter API. See figure 7.

71
Figure 7: Retrieve tweets user story

In case you used FlexUnit 1 you recall that each method you create must start with “test”, to enable the test runner to recognize the method. As a result, the method name was changed to testAdditionMethod. In FlexUnit 4, method names do not need to start with “test”; instead they are recognized by the [test] metadata, so feel free to refactor the method names to names that most suite your need.

The first step in implementing the first user story is to understand what’s your goal here. In our case we are testing that the service is working correctly. We are using a public API that is maintained by Twitter and creating a Mashup application. Using a well maintain API helps us creating our application quickly, however it also store a disadvantage that in any time Twitter may change their API and our application will stop working. We are testing that the fail and success events are dispatching correctly and ensuring that the API is working, see the code below:


package flexUnitTests
{
	import flash.events.Event;

	import flexunit.framework.Assert;

	import org.flexunit.async.Async;

	import utils.TwitterHelper;

	public class TwitterHelperTester
	{
		// Reference declaration for class to test
		private var classToTestRef : utils.TwitterHelper;

		public function TwitterHelperTester()
		{
		}

		[Test(async,timeout="500")]
		public function testRetrieveTweetsBasedOnHashTag():void
		{
                              classToTestRef = new TwitterHelper();
			var EVENT_TYPE:String = "retrieveTweets";

			classToTestRef.addEventListener(EVENT_TYPE, Async.asyncHandler( this,  handleAsyncEvnet, 500 ), false, 0, true );
			classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "http://search.twitter.com/search.json");
		}

		//--------------------------------------------------------------------------
		//
		//  Asynchronous handlers
		//
		//--------------------------------------------------------------------------

		private function handleAsyncEvnet(event:Event, passThroughData:Object):void
		{
			Assert.assertEquals( event.type, "retrieveTweets" );
		}
	}
}

As you can see we are writing a test that the method that calls the twitter API works and it retrieve results. We are referencing a method that doesn’t exist: retrieveTweetsBasedOnHashTag.

FlexUnit 4 incorporated Fluint functionality and it supports enhanced asynchronous and includes asynchronous setup and teardown. This feature is possible by every test including the overhead of the asynchronous script. Notice that we are setting a meta data with a timeout:


[Test(async,timeout="500")]

The test will wait 500 milliseconds for to get retrieveTweets dispatched meaning that the results have been retrieved.

Working on the compilation errors

Save the file and now you see a compile time error:

Call to a possibly undefined method retrieveTweetsBasedOnHashTag through a reference with static type utils:TwitterHelper.

This is actually a good. The compiler is telling you what you need to do next. We can now create the method in TwitterHelper in order to get rid of the compiler error.


package utils
{
     import flash.events.EventDispatcher;
     import flash.events.IEventDispatcher;

     public class TwitterHelper extends EventDispatcher
     {
          public function TwitterHelper(target:IEventDispatcher=null)
          {
               super(target);
          }

		  /**
		   * Method to send a request to retrieve all the tweet with a HashTag
		   * @param hashTag defined hashtag to search
		   *
		   */
		  public function retrieveTweetsBasedOnHashTag(hashTag:String):void
		  {
			  // implement
		  }
     }
}

Notice that I only wrote the minimum code to get rid of the compiler error, I haven’t implemented the method yet.

Compile the project and we don’t have any compile time errors and you can run the tests. Select the Run icon carrot and in the drop menu select FlexUnit Tests.

8

Figure 8: Start FlexUnit tests top menu

Once you selected the Run FlexUnit Tests a wizard gives you the opportunity to select entire classes or individual methods. Select TwitterHelperTester and hit OK, see Figure 9.

9

Figure 9: Select and run FlexUnit Tests window

Review the Results

Flash Builder opens a new window where the tests are run and shows the results of your test, see below:

• 1 total test was run
• 0 were successful
• 1 was a failure
• 0 were errors
• 0 were ignored

10

Figure 10: FlexUnit Test Run results

After the result window shows up you can close it and review the results in Flash Builder

• Close the web browser that was opened by builder
• You should see a new view opened in your Flash Builder called FlexUnit Results
• If you don’t see the window select: Windows > Other Views > Flash Builder > FlexUnit Results will open it
• The Results view will show you similar information to the web browser with much more detail and interactivity
• Note the Red Bar and double click on testSampleMethod in the results view (see Figure 11).
• Flash Builder will take you to that method in your code.
• Note that the failure message in the Failure Trace is the same as the contents of the Assert.fail call.

111

Figure 11: FlexUnit result view in Eclipse

The results view provides several action buttons worth reviewing see Figure 12.
12
Figure 12: results view options

Change the Test from Fail to Pass

In order to pass the test you now need to write the actual code. At this point we wrote the test and once we write the code the test will succeed. I have implemented the code to call Twitter and retrieve results that includes #FlashAndTheCity hashtag, see below:


package utils
{
	import com.adobe.serialization.json.JSON;

	import flash.events.EventDispatcher;

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

	public class TwitterHelper extends EventDispatcher
	{
		/**
		 * Holds the service class
		 */
		private var service:HTTPService;

		//--------------------------------------------------------------------------
		//
		//  Default Constructor
		//
		//--------------------------------------------------------------------------
		public function TwitterHelper()
		{
			// implement
		}

	   /**
	    * Method to send a request to retrieve all the tweet with a HashTag
	    * @param hashTag defined hashtag to search
	    * @url	the twitter API url
	    *
	    */
	   public function retrieveTweetsBasedOnHashTag(hashTag:String, url:String):void
	   {
		   service = new HTTPService();
		   service.url = url;
		   service.resultFormat = "text";

		   service.addEventListener(ResultEvent.RESULT, onResults);

		   var object:Object = new Object();
		   object.q = hashTag;
		   service.send( object );
	   }

	   //--------------------------------------------------------------------------
	   //
	   //  Event handlers
	   //
	   //--------------------------------------------------------------------------

	   /**
	    * Method to handle the result of a request to retrieve all the list
	    * @param event
	    *
	    */
	   private function onResults(event:ResultEvent):void
	   {
		   service.removeEventListener(ResultEvent.RESULT, onResults);
		   service.removeEventListener(FaultEvent.FAULT, onFault);

		   var rawData:String = String( event.result );
		   var object:Object = JSON.decode( rawData );
		   var results:Array = object.results as Array;
		   var collection:Vector.<TweetVO> = new Vector.<TweetVO>;

		   results.forEach( function callback(item:*, index:int, array:Array):void {
			   var tweet:TweetVO = new TweetVO( item.from_user, item.from_user_id, item.geo, item.id,
				   item.profile_image_url, item.source, item.text, item.to_user, item.to_user_id );

			   collection.push( tweet );
		   });

		   // dispatch an event that holds the results
		   this.dispatchEvent( new TwitterHelperSuccessEvent( collection ) );
	   }
	}
}

Notice that I am using JSON class, which is part of AS3 CoreLib (http://code.google.com/p/as3corelib/)

Additionally, in order to achieve the test I decided to do few things such as creating a Value Object (VO) to hold the results and create a custom event that will be dispatch once the results are retrieved. The VO holds must of the properties retrieved from Twitter API, see complete code below:


package utils
{
	[Bindable]
	public final class TweetVO
	{
		public var from_user:String;
		public var from_user_id:int;
		public var geo:String;
		public var id:int;
		public var profile_image_url:String;
		public var source:String;
		public var text:String;
		public var to_user:String;
		public var to_user_id:int;		

		public function TweetVO(from_user:String, from_user_id:int, geo:String, id:int, profile_image_url:String,
							source:String, text:String, to_user:String, to_user_id:int)
		{
			this.from_user = from_user;
			this.from_user_id = from_user_id;
			this.geo = geo;
			this.id = id;
			this.profile_image_url = profile_image_url;
			this.source = source;
			this.text = text;
			this.to_user = to_user;
			this.to_user_id = to_user_id;
		}
	}
}

Additionally, I have created a custom event that will hold the constant event type and allow passing the collection of tweets received, see complete code below:


package utils
{
	import flash.events.Event;

	public class TwitterHelperSuccessEvent extends Event
	{
		public static const RETRIEVE_TWEETS:String = "retrieveTweets";

		public var collection:Vector.<TweetVO>;

		public function TwitterHelperSuccessEvent( collection:Vector.<TweetVO> )
		{
			this.collection = collection;
			super( RETRIEVE_TWEETS );
		}
	}
}

Keep it simple: to the sake of simplicity I am keeping all the classes related to our class under the same package but feel free to refactor and place the event under an event folder. Also I haven’t implemented the clone method, which is recommended, but feel free to add these changes.

Run the test again and observe the results, see Figure 13.

• A test that does not fail succeeds
• Click the Run Completed Button
• Observe the Green Bar that indicates success

13
Figure 13: FlexUnit results view showing green bar

One thing to note is that I have set the service to 500 milliseconds, however the request took longer and I the test still failed so I quickly adjusted the code to wait 20000 milliseconds (20 seconds) to accommodate cases where the network is slow, feel free add a test to ensure the respond is quick enough.

To complete the user story we need to also test fault request, so just as we did before let’s write the test and than implement the code.

Add the following test:


[Test(async,timeout="20000")]
		public function testRetrieveTweetsBasedOnHashTagFail():void
		{
                              classToTestRef = new TwitterHelper();
			var EVENT_TYPE:String = "serviceFailure";

			classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this,  handleAsyncFaultEvnet, 20000 ), false, 0, true );
			classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "");
		}

		private function handleAsyncFaultEvnet(event:Event, passThroughData:Object):void
		{
			Assert.assertEquals( event.type, "serviceFailure" );
		}

Run the test and watch the fail results. Refactor TwitterHelper to include the fail method.


 	   public function retrieveTweetsBasedOnHashTag( hashTag:String, url:String ):void
	   {
		   service = new HTTPService();
		   service.url = url;
		   service.resultFormat = "text";

		   service.addEventListener(ResultEvent.RESULT, onResults);
		   service.addEventListener(FaultEvent.FAULT, onFault);

		   var object:Object = new Object();
		   object.q = hashTag;
		   service.send( object );
	   }

	   /**
	    * Holds the fault method in case the service failed
		 *
	    * @param event
	    *
	    */
	   private function onFault(event:FaultEvent):void
	   {
		   service.removeEventListener(ResultEvent.RESULT, onResults);
		   service.removeEventListener(FaultEvent.FAULT, onFault);

		   this.dispatchEvent( new TwitterHelperFailureEvent( event.fault.message ) );
	   }

Make sure to create the custom event for the fail event:


package utils
{
	import flash.events.Event;

	public class TwitterHelperFailureEvent extends Event
	{
		public static const SERVICE_FAILURE:String = "serviceFailure";

		public var message:String;

		public function TwitterHelperFailureEvent( message:String )
		{
			this.message = message;
			super( SERVICE_FAILURE );
		}
	}
}

Test again and you should see a green light, see Figure 14.

14
Figure 14: Result view showing our two test completed successfully

Refactor

At this point, we can do a small refactoring to the test case and include the static method from the custom event instead of having the string attached, which will ensure our tests still pass in case we refactor the event type string, see code below:


		[Test(async,timeout="20000")]
		public function testRetrieveTweetsBasedOnHashTag():void
		{
                              classToTestRef = new TwitterHelper();
			var EVENT_TYPE:String = TwitterHelperSuccessEvent.RETRIEVE_TWEETS;

			classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this,  handleAsyncEvnet, 20000 ), false, 0, true );
			classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "http://search.twitter.com/search.json");
		}

		[Test(async,timeout="20000")]
		public function testRetrieveTweetsBasedOnHashTagFail():void
		{
                              classToTestRef = new TwitterHelper();
			var EVENT_TYPE:String = TwitterHelperFailureEvent.SERVICE_FAILURE;

			classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this,  handleAsyncFaultEvnet, 20000 ), false, 0, true );
			classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "");
		}

Tests have duplication that can become painful to maintain

• In our case, we need to instantiating TwitterHelper in each test.
• Granted, there are just two, but this will grow
• We can solve this problem by using additional metadata provided by FlexUnit 4 called [Before] and [After]
• [Before] can be applied to any method that you wish called before each test.
• [After] will be called after each test

For good measure, let’s add a method name tearMeDown() and mark it with the [After] metadata.

• The [After] method gives you a place to clean up from your test case.
• In this case just set classToTestRef equal to null so the instance is available for garbage collection
• In more complicated tests it is often crucial to remove listeners, etc. in this way. In our case TwitterHelper is already removing the listeners so we don’t need to do that, but many other times you will.


		[Before]
		public function setMeUp():void
		{
			classToTestRef = new TwitterHelper();
		} 

		[After]
		public function tearMeDown():void
		{
			classToTestRef = null;
		}

See the complete test code below:


package flexUnitTests
{
	import flash.events.Event;

	import flexunit.framework.Assert;

	import org.flexunit.async.Async;

	import utils.TwitterHelper;
	import utils.TwitterHelperFailureEvent;
	import utils.TwitterHelperSuccessEvent;

	public class TwitterHelperTester
	{
		// Reference declaration for class to test
		private var classToTestRef : utils.TwitterHelper;

		public function TwitterHelperTester()
		{
		}

		[Before]
		public function setMeUp():void
		{
			classToTestRef = new TwitterHelper();
		} 

		[After]
		public function tearMeDown():void
		{
			classToTestRef = null;
		}		

		[Test(async,timeout="20000")]
		public function testRetrieveTweetsBasedOnHashTag():void
		{
			var EVENT_TYPE:String = TwitterHelperSuccessEvent.RETRIEVE_TWEETS;

			classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this,  handleAsyncEvnet, 20000 ), false, 0, true );
			classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "http://search.twitter.com/search.json");
		}

		[Test(async,timeout="20000")]
		public function testRetrieveTweetsBasedOnHashTagFail():void
		{
			var EVENT_TYPE:String = TwitterHelperFailureEvent.SERVICE_FAILURE;

			classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this,  handleAsyncFaultEvnet, 20000 ), false, 0, true );
			classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "");
		}		

		//--------------------------------------------------------------------------
		//
		//  Asynchronous handlers
		//
		//--------------------------------------------------------------------------

		private function handleAsyncEvnet(event:Event, passThroughData:Object):void
		{
			Assert.assertEquals( event.type, "retrieveTweets" );
		} 		

		private function handleAsyncFaultEvnet(event:Event, passThroughData:Object):void
		{
			Assert.assertEquals( event.type, "serviceFailure" );
		}
	}
}

In addition to refactor the tests you should also refactor the actual code. We focus on passing the test and didn’t care that much about the code, however you may find out that the code is too complex and can be simplify by implementing a design pattern, or just adding some small modification. For instance, I can add metadata so when you instantiate the class and add event listeners in MXML component you will get the event type available automatically. Add the code below to the TwitterHelper class:


	/**
	 *  Success custom event
	 *
	 *  @eventType utils.TwitterHelperSuccessEvent.RETRIEVE_TWEETS
	 */
	[Event(name="retrieveTweets", type="utils.TwitterHelperSuccessEvent")]

	/**
	 *  Failure custome event
	 *
	 *  @eventType utils.TwitterHelperFailureEvent.SERVICE_FAILURE
	 */
	[Event(name="serviceFailure", type="utils.TwitterHelperFailureEvent")]

You can see the complete code for the TwitterHelper class below:


package utils
{
	import com.adobe.serialization.json.JSON;

	import flash.events.EventDispatcher;

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

	/**
	 *  Success custom event
	 *
	 *  @eventType utils.TwitterHelperSuccessEvent.RETRIEVE_TWEETS
	 */
	[Event(name="retrieveTweets", type="utils.TwitterHelperSuccessEvent")]

	/**
	 *  Failure custome event
	 *
	 *  @eventType utils.TwitterHelperFailureEvent.SERVICE_FAILURE
	 */
	[Event(name="serviceFailure", type="utils.TwitterHelperFailureEvent")]	

	public class TwitterHelper extends EventDispatcher
	{
		/**
		 * Holds the service class
		 */
		private var service:HTTPService;

		//--------------------------------------------------------------------------
		//
		//  Default Constructor
		//
		//--------------------------------------------------------------------------
		public function TwitterHelper()
		{
			// implement
		}

	   /**
	    * Method to send a request to retrieve all the tweet with a HashTag
	    * @param hashTag defined hashtag to search
		* @url	the twitter API url
	    *
	    */
	   public function retrieveTweetsBasedOnHashTag( hashTag:String, url:String ):void
	   {
		   service = new HTTPService();
		   service.url = url;
		   service.resultFormat = "text";

		   service.addEventListener(ResultEvent.RESULT, onResults);
		   service.addEventListener(FaultEvent.FAULT, onFault);

		   var object:Object = new Object();
		   object.q = hashTag;
		   service.send( object );
	   }

	   //--------------------------------------------------------------------------
	   //
	   //  Event handlers
	   //
	   //--------------------------------------------------------------------------

	   /**
	    * Method to handle the result of a request to retrieve all the list
	    * @param event
	    *
	    */
	   private function onResults(event:ResultEvent):void
	   {
		   service.removeEventListener(ResultEvent.RESULT, onResults);
		   service.removeEventListener(FaultEvent.FAULT, onFault);

		   var rawData:String = String( event.result );
		   var object:Object = JSON.decode( rawData );
		   var results:Array = object.results as Array;
		   var collection:Vector.<TweetVO> = new Vector.<TweetVO>;

		   results.forEach( function callback(item:*, index:int, array:Array):void {
			   var tweet:TweetVO = new TweetVO( item.from_user, item.from_user_id, item.geo, item.id,
				   item.profile_image_url, item.source, item.text, item.to_user, item.to_user_id );

			   collection.push( tweet );
		   });

		   // dispatch an event that holds the results
		   this.dispatchEvent( new TwitterHelperSuccessEvent( collection ) );
	   }

	   /**
	    * Holds the fault method in case the service failed
		 *
	    * @param event
	    *
	    */
	   private function onFault(event:FaultEvent):void
	   {
		   service.removeEventListener(ResultEvent.RESULT, onResults);
		   service.removeEventListener(FaultEvent.FAULT, onFault);

		   this.dispatchEvent( new TwitterHelperFailureEvent( event.fault.message ) );
	   }
	}
}

Retrieve tweets every few seconds User Story

The second user story objective is to call the same method we just created every X seconds so we can keep retrieving tags that contain FlashAndTheCity keyword from Twitter, see Figure 15.

151
Figure 15: Retrieve tweets every few seconds User Story

This type of logic doesn’t have to be included in the utility class we created since it’s a specific implementation of the class and I prefer to keep the class generic so it can be re-used.

In the application I am creating I decided to avoid using any micro-architecture framework since the application is simple in nature and I am the only developer working on the application so no need to add complexity.

The architecture I prefer to implement is to separate the API from the implementation and handle this logic in the actual implementation of the class rather than the utility class. To achieve that I will create a design patter that will help me to separate the view and logic. It’s highly recommended to use some sort of presentation model (also known as code behind), so you can easily separate the data and logic from the view, state and transitions (animations).

This type of separation will allow you to better test your code. In my case I decided to implement the Passive Presentation Model, but there are many other ways to achieve the same goal. I am not going to go into too much detail, but feel free to visit the following link to find out more:
http://blogs.adobe.com/paulw/archives/2007/11/presentation_pa_6.html#more

Since we are using a different class for the implementation this user story I would create a new test case for this class. If you recall last time we created the class before the test case, this time I will create the Test Case and once I get compile time error I will add the class.

Create a new Test Case and fill in the information below, see Figure 16.

• Use TweetListPresenterTester as the name
• New FlexUnit 4 test
• Select Finish

16

Figure 16: Create TweetListPresenterTester Test Case Class

Make sure to add a reference of the Test Case to the Test Suite, otherwise it wont run the test.


package flexUnitTests
{
	[Suite]
	[RunWith("org.flexunit.runners.Suite")]
	public class CompanionTestSuite
	{
		public var twitterHelperTester:TwitterHelperTester;
		public var tweetListPresenterTester:TweetListPresenterTester;
	}
}

The unit test will include a reference to the presenter and will test the method that retrieve tweets every few seconds.


package flexUnitTests
{
	import flexunit.framework.Assert;

	import org.flexunit.async.Async;

	import utils.TwitterHelperSuccessEvent;

	public class TweetListPresenterTester
	{
		// Reference declaration for class to test
		private var classToTestRef : presenter.TweetListPresenter;

		public function TweetListPresenterTester()
		{
     classToTestRef = new TweetListPresenter();
		}

		[Test(async,timeout="2000")]
		public function testRetrieveTweetsEveryFewSeconds():void
		{
			classToTestRef.twitterHelper.addEventListener( TwitterHelperSuccessEvent.RETRIEVE_TWEETS, Async.asyncHandler( this, handleAsyncTweetSuccessEvnet, 2000 ), false, 0, true );
			classToTestRef.retrieveTweetsEveryFewSeconds( 4 );
		}

		//--------------------------------------------------------------------------
		//
		//  Asynchronous handlers
		//
		//--------------------------------------------------------------------------

		private function handleAsyncTweetSuccessEvnet(event:TwitterHelperSuccessEvent, passThroughData:Object):void
		{
			Assert.assertTrue( event.collection.length > 0 );
		}
	}
}

After you compile the application you will get the following compile time errors:

1. Type was not found or was not a compile-time constant: TweetListPresenter
2. Call to a possibly undefined method retrieveTweetsEveryFewSeconds through a reference with static type presenter:TweetListPresenter
3. Access of possibly undefined property twitterHelper through a reference with static type presenter:TweetListPresenter.

Once again, these compile time errors are a good thing, so our first task is to solve these errors by creating the TweetListPresenter class, method retrieveTweetsEveryFewSeconds and property twitterHelper. The test will start the method that should create a timer and call the service every four seconds. Once the service is called we should retrieve some data to indicate that the test succeeded.

I have created TweetListPresenter class and added the method and property so the compile time errors will be fixed see code below:


package presenter
{
	import utils.TwitterHelper;

	public class TweetListPresenter
	{
		public var twitterHelper:TwitterHelper;

		public function TweetListPresenter()
		{
			twitterHelper = new TwitterHelper();
		}

		public function retrieveTweetsEveryFewSeconds( seconds:int ):void
		{
			// implement
		}
	}
}

Run the test and you will see that it fails since we haven’t created the logic yet, see Run FlexUnit Tests wizard below.

17

171
Figure 17: Run FlexUnit Tests wizard to test testRetriveTweetsEveryFewSeconds method

18
Close the results view and observe the results, see Figure 18.

Figure 18: Results view shows testRetriveTweetsEveryFewSeconds have failed

As I explained the utility class we created is a wrapper for the Twitter API and doesn’t include any implementation logic, with that said by creating a presenter we can separate the view from the logic and better test the implementation logic.

The approach is to create a passive presenter that controls the view components passively. Create the application entry point and paste the following code, which will add a view to the application and pass that view to the presenter so it can adjust the view properties, such as adding a list of tweets to a datagrid:


<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
					   xmlns:s="library://ns.adobe.com/flex/spark"
					   xmlns:mx="library://ns.adobe.com/flex/halo"
					   xmlns:view="view.*"
					   creationComplete="creationCompleteHandler()">
	<fx:Script>
		<![CDATA[
			import presenter.TweetListPresenter;

			private var tweetListPresenter : TweetListPresenter;

			protected function creationCompleteHandler():void
			{
				tweetListPresenter = new TweetListPresenter( tweetListView );
			}

		]]>
	</fx:Script>

	<view:TweetListView id="tweetListView" />

</s:WindowedApplication>

Notice that we are passing an instance of the view so we can control the view based on the logic in the presenter class. Next adjust the constructor in the presenter class:


		// Corresponding view
		private var _tweetListView : TweetListView;

		public function TweetListPresenter( tweetListView:TweetListView )
		{
			_tweetListView = tweetListView;

			twitterHelper = new TwitterHelper();
		}

Additionally, create an empty view and name it TweetListView.mxml that we will be using to place the view components and sub-components once we are ready:


<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
		 xmlns:s="library://ns.adobe.com/flex/spark"
		 xmlns:mx="library://ns.adobe.com/flex/halo"
		 width="400" height="300">

</s:Group>

At this point we can compile the application and see an empty screen since we didn’t added any view components.

Write code

We are now ready to write the code needed for our test to pass.


package presenter
{
	import flash.events.TimerEvent;
	import flash.utils.Timer;

	import mx.collections.ArrayCollection;

	import utils.TweetVO;
	import utils.TwitterHelper;
	import utils.TwitterHelperFailureEvent;
	import utils.TwitterHelperSuccessEvent;

	import view.TweetListView;

	public class TweetListPresenter
	{
		/**
		 * Corresponding view
		 */
		private var _tweetListView : TweetListView;

		/**
		 *  Twitter helper utility class instance
		 */
		public var twitterHelper:TwitterHelper;

		/**
		 *   Holds a timer so we will be able to update list
		 */
		public var timer:Timer;

		//--------------------------------------------------------------------------
		//
		//  Default Constructor
		//
		//--------------------------------------------------------------------------

		public function TweetListPresenter( tweetListView:TweetListView )
		{
			_tweetListView = tweetListView;

			twitterHelper = new TwitterHelper();
			twitterHelper.addEventListener( TwitterHelperSuccessEvent.RETRIEVE_TWEETS, onRetrieveTweets );
			twitterHelper.addEventListener( TwitterHelperFailureEvent.SERVICE_FAILURE, onFaultRequest );
		}

		/**
		 * Method to go and retireve tweets every defined number of seconds
		 *
		 * @param seconds
		 *
		 */
		public function retrieveTweetsEveryFewSeconds( seconds:int ):void
		{
			timer = new Timer( seconds*1000, 100000 );
			timer.addEventListener(TimerEvent.TIMER, onTimerHandler);

			timer.start();
		}

		//--------------------------------------------------------------------------
		//
		//  Handlers
		//
		//--------------------------------------------------------------------------		

		/**
		 * Method to handle a timer event
		 *
		 * @param event
		 *
		 */
		private function onTimerHandler( event:TimerEvent ):void
		{
			twitterHelper.retrieveTweetsBasedOnHashTag( "FlashAndTheCity", "http://search.twitter.com/search.json" );
		}

		/**
		 * Handler for results
		 *
		 * @param event
		 *
		 */
		private function onRetrieveTweets( event:TwitterHelperSuccessEvent ):void
		{
			var dataProvider:Array = new Array();

			event.collection.forEach( function callback(item:TweetVO, index:int, vector:Vector.<TweetVO>):void {
				dataProvider.push( item );
			} );

			this._tweetListView.dataGrid.dataProvider = dataProvider;
		}

		/**
		 * Handler for fault
		 *
		 * @param event
		 *
		 */
		private function onFaultRequest( event:TwitterHelperFailureEvent ):void
		{

		}
	}
}

The code have a method called retrieveTweetsEveryFewSeconds, which starts a timer and allow us to call twitterHelper.retrieveTweetsBasedOnHashTag every few seconds. Add a DataGrid to the TweetListView.mxml so we can show the results;


<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
		 xmlns:s="library://ns.adobe.com/flex/spark"
		 xmlns:mx="library://ns.adobe.com/flex/halo"
		 width="400" height="300">

	<mx:DataGrid id="dataGrid" width="500" height="400" />

</s:Group>

Run the test and observe the passed test in the result view, see Figure 19:

19

Figure 19: Results View window showing testRetriveTweetsEveryFewSeconds Method passed

At this point you can also run the application and see the DataGrid shows results every four seconds, see Figure 20.
20

Figure 20: Companion application shows twitter results in a DataGrid

Refactor

I have done some additional refactoring to the code and you can download the complete project from here: Companion.fxp

Conclusion

This article covered Test Driven Development in Flex projects. We first defined the project we are creating by defining our user stories and than created the tests using FlexUnit 4. We followed the TDD process without suger coat the process, but showing a real realistic example you can follow and allow you to understand the process of using TDD.

After learning how to create FlexUnit test suites and test cases as well as follow the process, I hope you are inspired to use TDD on your mobile, web, and desktop Flash applications, and write better, more scalable, and more reusable code.

You can download the doc, preso and project files from here:
http://eladelrom-preso.googlecode.com/files/TDD.zip

Cheers :)

19
Dec

Adobe closed major security concerns with Flash Player 10.0.42.34 however these changes may effect the ability to access swfs when setting Security.allowDomain

It appears that Adobe closed some major security concerns with Flash Player 10.0.42.34 see here, however I believe these security concerns have changed the ability to access swf when setting Security.allowDomain.

ASDOC says:

“If two SWF files are served from different domains — for example, http://siteA.com/swfA.swf and http://siteB.com/siteB.swf — then, by default, Flash Player does not allow swfA.swf to script swfB.swf, nor swfB.swf to script swfA.swf. A SWF file gives SWF files from other domains by calling Security.allowDomain(). This is called cross-domain scripting. By calling Security.allowDomain(”siteA.com”), siteB.swf gives siteA.swf permission to script it.” > see here.

In the example below I am creating the example ASDOC is describing. I will create two application which will be hosted on two separate domain names, however I am unable to change properties in the accessed application, see detail below:

Accessed application will holds a label and set the Security.allowDomain to wild card (*) so any application should be able to load this swf and change properties. See below:


<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" preinitialize="application1_initializeHandler(event)">
	<fx:Script>
		<![CDATA[
			import mx.events.FlexEvent;

			protected function application1_initializeHandler(event:FlexEvent):void
			{
				Security.allowDomain("*");
			}

		]]>
	</fx:Script>

	<Label id="label" text="Hello from accessed application!"  x="8" y="9"/>

</s:Application>

The second application (accessing application) will be hosted on a separate domain and load the accessed swf and change the label property:


<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"
			   initialize="initializeHandler()">
	<fx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import mx.events.FlexEvent;

			// define variables
			private var loader:Loader;
			private var content:*;

			// load swf
			private function initializeHandler():void
			{
				loader = new Loader();
				loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadContent_onComplete);
				loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
				loader.load(new URLRequest("http://zeen.com/temp/bin-debug/AccessedApplication.swf"));

				component.addChild(loader);
			}

			// Event Handler

			private function loadContent_onComplete(event:Event):void
			{
				content = event.target.content;

				var onContentApplicationComplete:Function = function(event:Event):void
				{
					// content loaded successfully
				}

				content.addEventListener(FlexEvent.APPLICATION_COMPLETE, onContentApplicationComplete);
			}

			private function ioErrorHandler(event:IOErrorEvent):void
			{
				loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
				Alert.show(event.text);
			}

			private function securityErrorHandler(event:SecurityErrorEvent):void
			{
				loader.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
				Alert.show(event.text);
			}          

			// methods to access loaded swf

			private function callAccessedApplication():void
			{
				this.content.document.label.text = "label change!";
			}

		]]>
	</fx:Script>

	<mx:UIComponent id="component" width="400" height="82" x="11" y="43" />

	<Button label="Call accessed application"
			  click="callAccessedApplication()" x="84" y="0"/>   

</s:Application>

I also have set the cross-domain policy on the accessed applciation server to allow access:


<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
   <allow-access-from domain="*"/>
</cross-domain-policy> 

The swf is loaded successfully, but with a warning alert. Additionally, I am unable to change the label properties on the accessed application, see screen shot below:

screen-shot-2009-12-19-at-71327-pm

The application is hosted here:
http://eladelrom.com/bin-debug/AccessingApplication.html

I am hoping to get a clarification: https://bugs.adobe.com/jira/browse/FP-3513

01
Dec

Test Driven Development using Flash Builder 4 beta and FlexUnit on Devnet

There has been a great deal of interest in TDD (and unit testing in general) recently, because it leads to applications that are easier to scale and maintain and less prone to errors. I just published an article on Devnet that covered unit testing and Test Driven Development using Flash Builder 4 and FlexUnit, including some of the new features in the FlexUnit 4 framework.

Check it out here:
http://www.adobe.com/devnet/flex/articles/flashbuilder4_tdd_02.html

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 :)

05
Nov

Flex (Flash) Camp Wall Street conference in two weeks

I will be speaking this year at the Flex (Flash) Camp Wall Street conference. Although the recession is not over yet, the second edition of the prestige Flex (Flash) Camp Wall Street conference will be held in New York again. The event will be on November 16-17, 2009 and has a recession price of $49!

wallst

I am very excited for the opportunity to participate at the conference.
Speaker includes James Ward, Yakov Fain, Jeff Tapper, Jeffry Houser, Wade Arnold, Christian Saylor, Brian O’Connor, Daniel Holth and Adam Flater.

For more details goto:
http://www.flexcampwallstreet.com