Posts Tagged ‘Flex’

App Size: Flex vs Actionscript Project (Flex Framework Caching)

January 14, 2011

Following on from discussions at the ‘after’ part of last nights MMUG-Dublin meeting, I created a pure Actionscript 3 project and a similar Flex application project, both in Flex Builder 3. The aim was to compare final swf size. Both apps draw 3 circles on the screen.

Three circles, well done

Size Wise:

Flex 3 Application SWF (Release Build of Project): 169KB (but only 65KB with framework caching – see Optimization section below)

Pure Actionscript 3 Project SWF: 1KB

Optimization – Framework Caching

By default, the flex framework gets merged into your main swf file, adding around 100KB+. This can be avoided by going to Properties/Flex Build Path/Library Path/Framework Linkage/ and selecting Runtime Shared Library (RSL) from the dropdown. When you do a Build Release Project, your framework will be exported as a signed swz and an unsigned swf . These files should be placed in the same directory as your main swf file on the web server. In Flex 4, the framework RSL will automatically point to a public section of the Adobe site, where the swz’s will be available. Saves you having to host them.

The framework will only need to be downloaded by a particular client once, and will be cached by Flash Player, meaning every subsequent use of your app will not require downloading of the framework.swz (in the release will be named something like framework_3.2.0.3958.swz).

Read more about framework caching here: http://ted.onflash.org/2008/01/flex-3-framework-caching.php

Conclusion

If Actionscript will suffice e.g. for drawing three circles on the screen, go with a pure AS3 Project. If your developing data driven applications and user interfaces, use the Flex SDK (saves a tonne of time and effort, and whats 60kb these days – less than most peoples profile pics). Have a look at this Stackoverflow question for more opinions on each approaches pros and cons.

Code

Flex

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
	initialize="onInitialize()">
	<mx:Script>
		<![CDATA[
			import mx.core.UIComponent;

			private function onInitialize():void{
				drawCircle( 0x336699 );
	            drawCircle( 0x993333 );
	            drawCircle( 0x339933 );
			}

			private function drawCircle( color:uint ):void
	        {
	            var circle:Shape = new Shape();
	            var displayObject:UIComponent = new UIComponent();

	            circle.graphics.beginFill( color );
	            circle.graphics.lineStyle( 2, 0xCCCCCC );
	            circle.graphics.drawCircle( 30, 40, 30);
	            circle.graphics.endFill();
	            circle.x = (this.numChildren * 65) + 10;
	            circle.y = 0;

	            displayObject.addChild(circle);
	            this.addChild(displayObject);
	        }
		]]>
	</mx:Script>
</mx:Application>

Actionscript Project

package {
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;

	public class ActionScriptProject extends Sprite
	{
		public function ActionScriptProject()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            doDrawCircle( 0x336699 );
            doDrawCircle( 0x993333 );
            doDrawCircle( 0x339933 );
		}

		private function doDrawCircle( color:uint ):void
        {
            var child:Shape = new Shape();
            child.graphics.beginFill( color );
            child.graphics.lineStyle( 2, 0xCCCCCC );
            child.graphics.drawCircle( 30, 40, 30);
            child.graphics.endFill();
            child.x = (this.numChildren * 65) + 10;
            child.y = 0;
            addChild(child);
        }

	}
}

Module Optimization: Link report and load externs

January 12, 2011

When modules are released or built (using Clean or Project>Export Release Build..), the exported module swf’s will include any Flash/Flex framework classes and external swc/swf classes that are used by the modules.

This is not always optimal, as some of the files included in the Module’s swf’s may already be in used by the Main app, and included in the MainApp.swf. You can remove the overlapping classes from the module swf’s by doing the following:

  1. In your main app i.e. the one that will use the module, go to Project>Properties>Flex Compiler and add an Additional compiler arguments:

-link-report=link_report.xml

  1. Clean or Export Release Build the project.
  2. Copy the link_report.xml file from the bin-debug or bin-release folder and paste it to the root of the module project folder i.e. the same folder as the Module.mxml file(s).
  3. Repeat step 1 for the Modules project, and add the compiler arguments:

-load-externs=link_report.xml

  1. Clean or Export Release Build the project.

The released module swf’s will not include any external files that it shares with the main app. Reduced the size of the module I was optimizing in work by 15%!

Additional Compiler Arguments

More details on the compiler arguments and module optimization from:

http://livedocs.adobe.com/flex/3/html/help.html?content=modular_4.html

Caution: any time you change your main app, and remove or change dependencies or SDK versions, you will need to repeat the above process. The modules will not work with apps that they have not been optimized for.

If you receive an error message -load-externs “could not open …..”, make sure that the xml file is at the root of the module project.

API (SWC) “Code Navigation Error” when Ctrl+Left Click in Flex Builder

November 22, 2010

You’ve added your SWC to the build path, and it works fine. But, when you want to view a source file (ctrl+left click on the function name for example), you get an error. This use to bug me.

You need to edit the Source Attachment directory location in the Build Path (right click on the project name, and click properties/build path). Click the edit button for the Source Attachment, and point to the ‘src ‘ folder of the api zip file you downloaded. It may be the case that your import statement looks like “import com.mc.components.MyComponent;” but the file structure is src/main/flex/com/mc/.. : in this case set the source attachment folder to point to ..src/main/flex, i.e. the last folder before the imported package.

Flex Builder - src build path

Flex: testing/running php proxy locally

October 15, 2010

When accessing URL’s through HttpServices from a remote domain, it often works fine on the local system but fails to connect when the swf is uploaded to the web (google searh ‘flex crossdomain.xml proxy’).

A common way around this is to place a PHP file on your web server that acts as a go-between for the remote site and the swf (an example discussed on Dennis Jaamaan’s site, with proxy code).

This article explains how to setup a local PHP server, and test your PHP proxy locally through Flex Builder 3

1. Download a PHP server: http://www.wampserver.com/en/download.php

2. Install it, leaving whatever default settings it suggests.

3. Click the WampServer taskbar icon, and go to PHP/PHP_extensions/ and click php_curl (need to enable this to use the example below). Then click Start All Services & Put Online.

4. Create a php file named flexProxy.php and put in the code below:

<?php
$ch = curl_init();
$timeout = 30;
$userAgent = $_SERVER['HTTP_USER_AGENT'];

$url = $_REQUEST['url'];
$place = $_REQUEST['place'];

$fullGoogleWeatherPath = $url . $place;

curl_setopt($ch, CURLOPT_URL,$fullGoogleWeatherPath);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);

$response = curl_exec($ch);

if (curl_errno($ch)) {
    echo curl_error($ch);
} else {
    curl_close($ch);
    echo $response;
}
?>

5. Save this file and put it in the localhost directory: C:\wamp\www\

Read the rest of this article…………….

Country – Capital XML List using GeoNames

October 15, 2010

Was looking around trying to find an XML file of countries and capital cities.

Initially came accross some rather incomplete xml files with the ISO two digit country codes, but so far the best info I found is from GeoNames.

If your using Flash/Flex, it doesnt matter that their crossdomain.xml is outdated, because they use REST web services.

e.g.  http://ws.geonames.org/countryInfo?

In flex, you can use a HttpService to specify request attributes, good example here. Very handy.

Flex web service, WSDL crossdomain.xml

October 15, 2010

If you’re building a Flex web app utilising wsdl webservices, dont bother using http://www.webservicex.net services, they hav’nt updated their crossdomain.xml file to include the necessary Flash 9/10 XML elements. Any web service calls will result in a URL FaultEvent error. I have contacted them, so hopefully they will update it. The crossdomain.xml file (of your site as well) should contain the following element:

<allow-http-request-headers-from domain="*" headers="*" />

Go to any sites root address to check it out e.g.  http://www.xignite.com/crossdomain.xml

Easing/tweened Flex Scrolling Canvas

July 27, 2010

I was looking to add some acceleration/easing to the scrolling of a Flex container.

I used Tweener API and applied it to a Flex Canvas (the canvas has its scrolling policies turned off, and scrolling is provided with an external/floating scrollbar).

You can see the Tweener trainsitions on their online documentation here (click on ‘transition types’).

Full code after the jump ………………

Example multidimensional / 3D indexed array in Flex AS3

July 26, 2010

Scenario: I recently created a Flex component that extended the Canvas, and was split into a large number of ‘cells’ using constraint rows/columns. In each of these cells could be placed any number of UIComponents.

Problem: At any time I could tell what cell I was mousing over e.g.  (0,1), but I also needed to get an array of the components in that cell. It was not optimal iterating accross all the UIComponents on the canvas to check their constraint row/column id’s to find the relevant ones.

Solution: Created a 3D indexed array with references to each cell’s UIComponents. To retrieve the components from cell (3, 5) I would simply use: resultsArray = _cellComponents[rowNum][columnNum];

The image below represents a basic 3D array, with each cell containing just random objects: ints, strings and an image object. The sample app code that follows shows you how to create and populate a 3D array, and has a simple interface so you can test retrieving the stored objects.

3D array visual

Simple UI for 3D Array


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
	<mx:Script>
		<![CDATA[
			import mx.controls.Image;
			import mx.controls.Button;
			import mx.events.IndexChangedEvent;
			
			private var _array3D:Array = new Array();
			private var _numRows:int = 2;
			private var _numColumns:int = 4;
			
			private function init():void{
							
				for(var i:int = 0; i < _numRows; i++){
					
					var rowArray:Array = new Array();
					_array3D.push(rowArray);
					
					// Create a 3d array (basically a 2d array of array objects)
					for(var j:int = 0; j < _numColumns; j++){
						
						var columnArray:Array = new Array();						
						_array3D[i].push(columnArray);									
					} 
				}
				
				// Populate a 3d array
				_array3D[0][0].push(1, 2, 3, 4);
				_array3D[0][3].push("A", "B", "C", "D");
				_array3D[1][0].push(5, 6, 7);
				_array3D[1][1].push(8);
				_array3D[1][2].push(9, 10);				
				// You can add any type of Object to the array.
				var image:Image = new Image();
				image.name = "arrayImage";			
				_array3D[1][3].push(image);
															
			}
			
			private function getValues(row:String, col:String):void{
				
				var r:int = parseInt(row);
				var c:int = parseInt(col);
				
				var cell:Array = _array3D[r][c];
				var output:String = "";
				
				if(cell != null){
					
					for(var i:int = 0; i <cell.length; i++){
						output = output + " " + cell[i].toString();
					}
					
					if(output == ""){
						outputText.text = "No data in cell"
					}
					else{
						outputText.text = output;
					}					
				}
				else{
					outputText.text = "Not a valid row/column";			
				}					
			}			
			
		]]>
	</mx:Script>

	<mx:Canvas id="myCanvas" x="65" y="49" width="308" height="99" backgroundColor="#FFFFFF">
		<mx:ApplicationControlBar x="0" y="0" width="100%">
			<mx:Label text="Row"/>
			<mx:TextInput id="row" width="56"/>
			<mx:Label text="Col."/>
			<mx:TextInput id="col" width="56"/>
			<mx:Button label="Get Values" click="getValues(row.text, col.text)"/>
		</mx:ApplicationControlBar>
		<mx:Text id="outputText" x="0" y="52" width="100%" textAlign="center"/>
	</mx:Canvas>
</mx:Application>

Flex: Date.month is zero-based, Date.date is one-based!!

July 7, 2010

This little issue caught me out a bit when debugging an app: the month property of a Flex Date object is zero-based, whereas the Date.date property is an integer from 1 to 31. Crazy or what!

For 07/07/2010 (07/July/2010) at 09:33 GMT, the date object is shown below:

Flex Date for 07/July/2010 09:33 GMT

Rounded Corners on Highlight and Selection Indicators for TileList

April 8, 2010

The TileList class has to be extended, and the following methods in the the TileList class need to be overridden:

  • drawSelectionIndicator
  • drawHighlightIndicator

TileList inherits from ListBase, and the source functions to override can be viewed here.

Example of how to extend the TileList class can be viewed in this very helpful post by Charlie Key.

The code below adds rounded corners to the selection and highlight indicators of the tilelist.

Rounded Corners TileList Items

override protected function drawSelectionIndicator(indicator:Sprite, x:Number,
    y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void
 {
    var g:Graphics = Sprite(indicator).graphics;
    g.clear();
    g.beginFill(color);
    g.drawRoundRect(0,0,width, height,20,20);
    g.endFill();

    indicator.x = x;
    indicator.y = y;
 }

 override protected function drawHighlightIndicator(indicator:Sprite, x:Number,
    y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void{

    var g:Graphics = Sprite(indicator).graphics;
    g.clear();
    g.beginFill(color);
    g.drawRoundRect(0,0,width, height,20,20);
    g.endFill();

    indicator.x = x;
    indicator.y = y;
 }