Conditional Compilation
There is a cool compiler flag that allows you to conditionally compile code into your binaries called -define.
This really cool feature has an annoying side effect though:
private function doSomething():void
{
if ( whatever == true )
{
//Do something
}
KEY::debug
{
else
{
trace("Some debug information here");
}
}
}
This throws a compile error. I have a lot of places in the code where in the else of a condition I just want to trace something out, but if I put the debug compiler statement just around the trace inside of the else, I get a compiler warning when using the command line tools:
/path/to/target: col: xx Warning: Empty statement found where block of code expected. Did you type ’;’ accidentally?
Sure, I can re-write the code with the debug stand alone with another IF condition that is the opposite of what the actual code is doing, but I think it is more natural and makes the code clearer to read later when maintaining to just optionally include the else in certain build environments.
Another option is to use another key, such as this:
private function doSomething():void
{
KEY::debug
{
if ( whatever == true )
{
//Do something
}
else
{
trace("Some debug information here");
}
}
KEY::release
{
if ( whatever == true )
{
//Do something
}
}
}
The obvious pitfall is code duplication, which is also bad for maintenance.
If you agree, you can vote here.
Data Binding Series
Ever {wonder} how data binding works? The magic of data binding is a combination of code generation by the flex pre-compiler and the Flex event model, which is an implementation of the observer pattern.
Lets start with a short description and overview of the observer pattern and events:
The observer pattern has two actors: the publisher, also known as the subject, and one or more subscribers, also known as the dependents, who register one or more methods to be invoked by the publisher at some point in the future.
In Flex terms, this would be any IEventDispatcher. When you say obj.addEventListener(blah, onWhatever), obj is the publisher of blah and the class adding the event listener (onWhatever callback) with obj is the dependent. An example:
Car.as, the subscriber or dependent, manually set up to listen for an event.
package examples
{
import flash.events.Event;
public class Car
{
private var _wheels:Vector.<Wheel>;
public function Car()
{
_wheels = new Vector.<Wheel>();
for ( var i:int = 0; i < 4; i++ )
{
var wheel:Wheel = new Wheel();
wheel.addEventListener(Wheel.ROTATE, onWheelRoll)
_wheels.push( wheel );
}
}
private function onWheelRoll(e:Event):void
{
}
}
}
Wheel.as, the publisher or subject, manually set up to dispatch an event.
package examples
{
import flash.events.Event;
import flash.events.EventDispatcher;
[Event(name="rotate", type="flash.events.Event")]
public class Wheel extends EventDispatcher
{
public static const ROTATE:String = "rotate";
private var _rotation:Number;
public function Wheel()
{
}
public function get rotation():Number
{
return _rotation;
}
public function set rotation(value:Number):void
{
_rotation = value;
dispatchEvent( new Event(ROTATE) );
}
}
}
Now that we have understanding of Flex events as an implementation of the Observer pattern, you will see that data binding is nothing more than a series of callbacks getting notified when an interest changes.
Just as there are two parts to the observer pattern, there are two parts to data binding; the subject and dependent. So how does the {binding syntax} get turned into something similar of the manual job seen in Car and Wheel above? Lets start with the subject.
Revised Wheel to make it bindable:
package examples.two
{
[Bindable]
public class Wheel
{
public var rotation:Number = 0;
public function Wheel()
{
}
}
}
A revised Car implementation as a bindable dependent.
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:two="examples.two.*">
<fx:Declarations>
<two:Wheel id="one"/>
<two:Wheel id="two"/>
<two:Wheel id="three"/>
<two:Wheel id="four"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
public function moveForward():void
{
for each ( var wheel:Wheel in [one, two, three, four] )
{
wheel.rotation++;
}
}
]]>
</fx:Script>
<s:Label text="Wheel 1 rotation: {one.rotation}, Wheel 2 rotation: {two.rotation}, Wheel 3 rotation: {three.rotation}, Wheel 4 rotation: {four.rotation}"/>
<s:Button label="Move Forward" click="moveForward();"/>
</s:VGroup>
Lets use the -keep compiler flag and see the generated code. I’ve removed lots of comments and cut out some things just to make it readable here.
class BindableProperty implements flash.events.IEventDispatcher
{
[Bindable(event="propertyChange")]
public function get rotation():Number
{
return this._rotation;
}
public function set rotation(value:Number):void
{
var oldValue:Object = this._rotation;
if (oldValue !== value)
{
this._rotation = value;
if (this.hasEventListener("propertyChange"))
this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, "rotation", oldValue, value));
}
}
//Removed implementation of IEventDispatcher
}
There are a few things going on here, first of which is that a PropertyChangeEvent is dispatched when the value of rotation changes. If you’ve ever wondered why when you set a property on a bindable class that didn’t get updated in the view, 99% of the time, this is the reason. There are performance implications (in addition to the implications we will go over later) if the event was fired every time the property was set regardless of whether or not it was different, but if you know how binding works and set up the piping manually, as opposed to the binding syntax, you can manipulate “rules” such as these.
Next in the series we will learn about the overhead and some of the pitfalls of using binding, tools that binding uses such as ChainWatcher and BindingUtils, how binding works on properties or objects that simply don’t exist or are invalid, and how to customize the events that are dispatched by the subject when a bindable property is set.
Just for fun and if you don’t feel like browsing through the generated code, here is the Car MXML after my cleanup of the pre-compiler:
public class Car extends spark.components.VGroup implements mx.binding.IBindingClient
{
public var _Car_Label1 : spark.components.Label;
[Bindable] public var four : examples.two.Wheel;
[Bindable] public var one : examples.two.Wheel;
[Bindable] public var three : examples.two.Wheel;
[Bindable] public var two : examples.two.Wheel;
public function Car()
{
super();
var bindings:Array = _Car_bindingsSetup();
var watchers:Array = [];
var target:Object = this;
if (_watcherSetupUtil == null)
{
var watcherSetupUtilClass:Object = getDefinitionByName("_examples_two_CarWatcherSetupUtil");
watcherSetupUtilClass["init"](null);
}
_watcherSetupUtil.setup(this,
function(propertyName:String):* { return target[propertyName]; },
function(propertyName:String):* { return Car[propertyName]; },
bindings,
watchers);
mx_internal::_bindings = mx_internal::_bindings.concat(bindings);
mx_internal::_watchers = mx_internal::_watchers.concat(watchers);
this.mxmlContent = [_Car_Label1_i(), _Car_Button1_c()];
_Car_Wheel4_i();
_Car_Wheel1_i();
_Car_Wheel3_i();
_Car_Wheel2_i();
for (var i:uint = 0; i < bindings.length; i++)
{
Binding(bindings[i]).execute();
}
}
private var __moduleFactoryInitialized:Boolean = false;
override public function set moduleFactory(factory:IFlexModuleFactory):void
{
super.moduleFactory = factory;
if (__moduleFactoryInitialized)
return;
__moduleFactoryInitialized = true;
}
public function moveForward():void
{
for each ( var wheel:Wheel in [one, two, three, four] )
{
wheel.rotation++;
}
}
private function _Car_Wheel4_i() : examples.two.Wheel
{
var temp : examples.two.Wheel = new examples.two.Wheel();
four = temp;
mx.binding.BindingManager.executeBindings(this, "four", four);
return temp;
}
private function _Car_Wheel1_i() : examples.two.Wheel
{
var temp : examples.two.Wheel = new examples.two.Wheel();
one = temp;
mx.binding.BindingManager.executeBindings(this, "one", one);
return temp;
}
private function _Car_Wheel3_i() : examples.two.Wheel
{
var temp : examples.two.Wheel = new examples.two.Wheel();
three = temp;
mx.binding.BindingManager.executeBindings(this, "three", three);
return temp;
}
private function _Car_Wheel2_i() : examples.two.Wheel
{
var temp : examples.two.Wheel = new examples.two.Wheel();
two = temp;
mx.binding.BindingManager.executeBindings(this, "two", two);
return temp;
}
private function _Car_Label1_i() : spark.components.Label
{
var temp : spark.components.Label = new spark.components.Label();
temp.id = "_Car_Label1";
if (!temp.document) temp.document = this;
_Car_Label1 = temp;
mx.binding.BindingManager.executeBindings(this, "_Car_Label1", _Car_Label1);
return temp;
}
private function _Car_Button1_c() : spark.components.Button
{
var temp : spark.components.Button = new spark.components.Button();
temp.label = "Move Forward";
temp.addEventListener("click", ___Car_Button1_click);
if (!temp.document) temp.document = this;
mx.binding.BindingManager.executeBindings(this, "temp", temp);
return temp;
}
public function ___Car_Button1_click(event:flash.events.MouseEvent):void
{
moveForward();
}
private function _Car_bindingsSetup():Array
{
var result:Array = [];
result[0] = new mx.binding.Binding(this,
function():String
{
var result:* = "Wheel 1 rotation: " + (one.rotation) + ", Wheel 2 rotation: " + (two.rotation) + ", Wheel 3 rotation: " + (three.rotation) + ", Wheel 4 rotation: " + (four.rotation);
return (result == undefined ? null : String(result));
},
null,
"_Car_Label1.text"
);
return result;
}
public static function set watcherSetupUtil(watcherSetupUtil:IWatcherSetupUtil2):void
{
(Car)._watcherSetupUtil = watcherSetupUtil;
}
private static var _watcherSetupUtil:IWatcherSetupUtil2;
mx_internal var _bindings : Array = [];
mx_internal var _watchers : Array = [];
mx_internal var _bindingsByDestination : Object = {};
mx_internal var _bindingsBeginWithWord : Object = {};
}
Unknown error generating output application.xml files
I’ve been implementing a new project using the TDD methodology using some of the new flash builder tools – specifically the “Execute FlexUnit Tests” method when you right click on a test case class.
When the project matured enough to check into SVN, I noticed a weird error:
Unknown error generating output application.xml files.
The error said I should consult my eclipse .log file, and it had an entry like this one:
!ENTRY com.adobe.flexbuilder.project 4 43 2010-01-13 09:03:05.710
!MESSAGE Error generating application.xml
!STACK 1
org.eclipse.core.internal.resources.ResourceException: Resource is out of sync with the file system: ‘/ArbMvcUnitTests/src/FlexUnitApplication-app.xml’.
at org.eclipse.core.internal.localstore.FileSystemResourceManager.read(FileSystemResourceManager.java:664)
at org.eclipse.core.internal.resources.File.getContents(File.java:288)
at org.eclipse.core.internal.resources.File.getContents(File.java:277)
at com.adobe.flexbuilder.project.air.build.ApolloXMLBuilder.generateXmlFile(ApolloXMLBuilder.java:111)
at com.adobe.flexbuilder.project.air.build.ApolloXMLBuilder.build(ApolloXMLBuilder.java:77)
at com.adobe.flexbuilder.project.air.build.ApolloXMLIncrementalBuilder.build(ApolloXMLIncrementalBuilder.java:74)
at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:627)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:170)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:201)
at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:253)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:256)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:218)
at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:360)
at org.eclipse.core.internal.resources.Project$1.run(Project.java:523)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1800)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1782)
at org.eclipse.core.internal.resources.Project.internalBuild(Project.java:502)
at org.eclipse.core.internal.resources.Project.build(Project.java:94)
at org.eclipse.debug.core.model.LaunchConfigurationDelegate$1.run(LaunchConfigurationDelegate.java:423)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1800)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1782)
at org.eclipse.debug.core.model.LaunchConfigurationDelegate.buildProjects(LaunchConfigurationDelegate.java:430)
at org.eclipse.debug.core.model.LaunchConfigurationDelegate.buildForLaunch(LaunchConfigurationDelegate.java:126)
at com.adobe.flexide.launching.AbstractFlexLaunchDelegate.buildForLaunch(AbstractFlexLaunchDelegate.java:897)
at org.eclipse.debug.internal.core.LaunchConfiguration.launch(LaunchConfiguration.java:821)
at org.eclipse.debug.internal.core.LaunchConfiguration.launch(LaunchConfiguration.java:703)
at org.eclipse.debug.internal.ui.DebugUIPlugin.buildAndLaunch(DebugUIPlugin.java:866)
at org.eclipse.debug.internal.ui.DebugUIPlugin$8.run(DebugUIPlugin.java:1069)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
!SUBENTRY 1 org.eclipse.core.resources 4 274 2010-01-13 09:03:05.711
!MESSAGE Resource is out of sync with the file system: ‘/ArbMvcUnitTests/src/FlexUnitApplication-app.xml’.
I first went to the adobe pre-release site and found nothing, so I asked Google and it led me here.
While good to know, it didn’t help my problem. After fiddling around with settings and removing the file, I decided to post a bug and try the prerelease forums. They suggested I switch work spaces since they couldn’t reproduce the problem, which led me to believe that my metadata had somehow gotten jacked up.
Sort of… Apparently eclipse has a problem with generated files that SVN has tagged and can’t handle it appropriately. The solution is to do a propset svn:ignore on the transient files in stead of tagging them with SVN and magically no more compile error occurs… at least so far…
assertEquals using != and the difference between != and !==
When using the assertEquals method in Flexunit 4, it is important to understand how the != operator works.
I was under the assumption that != checked the values of the items on either side of the operand, while the !== checked the reference, but != checking values is only partially true.
The full details can be found here, but interestingly, the last bullet item states:
Variables representing objects, arrays, and functions are compared by reference. Two such variables are equal if they refer to the same object, array, or function. Two separate arrays are never considered equal, even if they have the same number of elements.
Wow, that’s kinda lame. I thought !== was supposed to check by reference? Regardless of the differences (you can find !== details here) and debate between what the two operands should do, the message I was getting when my assertEquals failed on two objects showed the same string message.
To add to my confusion, it just so happened that the two static classes I was comparing in the assertEquals method had toString() methods. When the asserEquals failed, the toString() method was called on each and returned the same value and I was getting something like
expected: <My String> but was: <My String>
If I didn’t have the toString method, I would have received the generic
expected: <object Type> but was: <object Type>
The bottom line when using the asserEquals method is to create some sort of comparison value and assert that those are equal. In my case, I changed assertEqual(obj1, obj2) to assertEqual(obj1.toString(), obj2.toString()). Maybe toString() can be used as a fallback inside of assertEquals since that would be used for the failure output anyways? I don’t know what the ramifications of that would be, and I really don’t want to think about it since asserting that toString() returns the same thing from both objects is acceptable in my case.
Passing the rest parameter
As you probably know, you can create a function where the last parameter is a “…rest” variable.
You probably also know that when inside the function, the comma delimited variables from the caller show up as an array. This is unfortunate when you want to pass the set of values through to another function.
Enter the apply function. What this means is that you can take the array that just came in and pass the parameters off to another function in the same manner it came in, as long as it isn’t a constructor. Adobe has deferred that until later.
<?xml version="1.0" encoding="utf-8"?>
<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="application1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.utils.ObjectUtil;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
one("this", "is", "a", "set", "of", "parameters");
}
private function one(...parameters):void
{
//Bummer, I can't send parameters down to two as it came in...
two(parameters);
//Or can I ?
two.apply(this, parameters);
//You can of course manipulate the rest parameter before passing it on...
parameters.unshift(parameters.shift(), "really");
two.apply(this, parameters);
}
private function two(...parameters):void
{
trace( ObjectUtil.toString(parameters) );
}
]]>
</fx:Script>
</s:Application>
Application global access
In flex 4, accessing your application globally has changed from Application.application in flex 3, to FlexGlobals.topLevelApplication.
Flex 3:
import mx.core.Application; var myApp:MyApp = Application.application as MyApp;
Flex 4:
import mx.core.FlexGlobals; var myApp:MyApp = FlexGlobals.topLevelApplication as MyApp;
<s:ItemRenderer/> currentState == null
I received an Item renderer from my designer with a few states that were to be driven by some data. We are using an advanced data grid and one of the columns is rendered by this component.
We noticed that the state wasn’t reflected by the data despite the correct state being set. As it turns out, the ItemRenderer class has a getCurrentRendererState() method that can potentially return null – Specifically when there is no interaction (hovered, selected, etc…) and there is no “normal” state on your renderer.
So despite my setting the correct state, this base method was hijacking me and setting the state to null. You can fix this problem by overriding the method, or by overriding “setCurrentState” and not calling super.setCurrentState if the stateName is null.
PUNQ 1.0 released
I’ve been working on a free IT Search tool for the past couple of months at my company called PUNQ.
See the official press release here, a summary on the tool here, and the you-tube help videos here.
I think the toughest part of the project was integrating the code base among platform specific features including a web (flex) version and an air version for desktop apps.
