Wednesday, July 16, 2008

A Timer for Cairngorm

I've been playing with Flex for a couple of years now, but until Gotcha, none of my apps were big enough to be difficult to read. At multiple points during the coding of Gotcha, I found myself trying desperately to avoid slipping in to spaghetti code territory.

Since then, I've started playing with Cairngorm. So far, I'm a fan, but every once in a while I run in to something that I can't immediately figure out how to fit in to the framework. One such example was the Timer. In particular, where do your TimerEvent listeners go?

A Google search showed me that I wasn't the only one who had this question, as evidenced by the comments here. The suggestions were to put the event listeners in the ModelLocator or in the main.mxml. Neither of those seems correct to me. To me, the obvious place for them is where all of your other event listeners go: the FrontController.

Unfortunately, TimerEvent listeners can't be wired up in the FrontController, at least not using the standard Cairngorm means, because TimerEvent is not a CairngormEvent. To solve this problem, I created the CairngormTimer.

CairngormTimer is a wrapper for Timer that dispatches CairngormEvents. The "type" of the CairngormEvent defaults to the same type of the TimerEvent, but it can be changed to easily facilitate having multiple CairngormTimers in the same program.

Here's the code for the CairngormTimer:


package net.coryhill.utils {

import flash.events.TimerEvent;
import flash.utils.Timer;
import com.adobe.cairngorm.control.CairngormEvent;

public class CairngormTimer {

private var _timer:Timer;
private var _timerEventType:String;
private var _timerCompleteEventType:String;

public function CairngormTimer(delay:Number,
timerEventType:String = "timer",
timerCompleteEventType:String = "timerComplete",
repeatCount:int = 0)
{
_timer = new Timer(delay, repeatCount);
_timerEventType = timerEventType;
_timerCompleteEventType = timerCompleteEventType;
}

public function get currentCount():int {
return _timer.currentCount;
}

public function get delay():Number {
return _timer.delay;
}
public function set delay(val:Number):void {
_timer.delay = val;
}

public function get repeatCount():int {
return _timer.repeatCount;
}
public function set repeatCount(val:int):void {
_timer.repeatCount = val;
}

public function get running():Boolean {
return _timer.running;
}

/** The type of the CairngormEvent to dispatch when the timer
has reached the specified interval. */
public function get timerEventType():String {
return _timerEventType;
}
public function set timerEventType(val:String):void {
_timerEventType = val;
}

/** The type of the CairngormEvent to dispatch when the timer
has completed the number of requests set by repeatCount. */
public function get timerCompleteEventType():String {
return _timerCompleteEventType;
}
public function set timerCompleteEventType(val:String):void {
_timerCompleteEventType = val;
}

public function start():void {
_timer.start();
_timer.addEventListener(TimerEvent.TIMER, timeHandler);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, timeCompleteHandler);
}

public function reset():void {
_timer.reset();
_timer.removeEventListener(TimerEvent.TIMER, timeHandler);
_timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timeCompleteHandler);
}

public function stop():void {
_timer.stop();
_timer.removeEventListener(TimerEvent.TIMER, timeHandler);
_timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timeCompleteHandler);
}

private function timeHandler(e:TimerEvent):void {
var ce:CairngormEvent =
new CairngormEvent(_timerEventType);
ce.data = this;
ce.dispatch();
}

private function timeCompleteHandler(e:TimerEvent):void {
var ce:CairngormEvent =
new CairngormEvent(_timerCompleteEventType);
ce.data = this;
ce.dispatch();
}
}

}

Your FrontController is set up to listen for these events and execute
the command that should react to your timer:

addCommand("timerTest", TimerCommand);

Now you can start or stop a CairngormTimer that dispatches the "timerTest" CairngormEvent wherever you want in your code:

var timer:CairngormTimer = new CairngormTimer(100, "timerTest");
timer.start();

This works well for me and I feel that it fits cleanly within the Cairngorm framework, but I would like to hear other peoples' thoughts.

2 comments:

flo said...
This comment has been removed by the author.
flo said...

it also works great for me! thank you for sharing your ideas and helping me solving my architecture problems!