-
http://alecmce.com Alec McEachran
-
http://alecmce.com Alec McEachran
-
http://www.ubervu.com/conversations/blog.vizio360.co.uk/2010/04/robotlegs-example-clock-app/ uberVU – social comments
-
http://joelhooks.com Joel Hooks
-
http://joelhooks.com Joel Hooks
-
Anonymous
-
vizio
-
Anonymous
-
vizio
-
http://twitter.com/markfoxisadj Mark Fox

RobotLegs Example – Clock App
20-09-2010 I’m currently re-factoring the Clockapp App as after submitting it to the RobotLegs Knowledge base I got back a list of things to fix, like I shouldn’t add views to other views in a command
. There is always stuff to learn!
If you are interested the re-factored app is in the BlockageReview branch here.
There is a lot of talking about RobotLegs Micro-Architecture Framework in the Flash community and, as it is derived from PureMVC Framework with which I had a really good relationship and because I would like to know if we can use it for our current project at work, I thought I give it a try.
To test it out I thought to implement one of the most simple yet clear example of a MVC application:
A clock which can display the time in different ways (e.g. Analog, Digital, or a TokyoFlash way check it out here ).
Clock MVC
So lets have a look at what can be the Model, Views and Controllers for a clock:
So for a clock we can say that the Model is the time itself.
In our case the Views are the representation of the time as Digital or Analog clocks.
For a clock a controller could be the tick mechanism that defines the change in the time.
But lets see some flashy things! Here is the final result for the Clock demo:
The code for this demo can be found here on gitHub:
feel free to clone it test it change it fork it do whatever you want with it!
Here is a diagram to describe the application:
ClockApp:
Main class of the application. This is where we initialize the RobotLegs Context to wire up all the components of the application.
ClockContext:
From the RobotLegs best practice
The context is where we map commands to events, map mediators to views and define model/service actors.
Mapping commands:
The context object has two important phases STARTUP and SHUTDOWN. In the clock demo I’ve mapped some commands to the STARTUP_COMPLETE event:
override public function startup():void { commandMap.mapEvent(ContextEvent.STARTUP_COMPLETE, SetupStage); commandMap.mapEvent(ContextEvent.STARTUP_COMPLETE, AddClocks); commandMap.mapEvent(ContextEvent.STARTUP_COMPLETE, AlignClocksOnStage); commandMap.mapEvent(ContextEvent.STARTUP_COMPLETE, StartClock); ...those commands will be executed in the sequence they are mapped, when the context fires the STARTUP_COMPLETE event.
Defining Model/Service actors:
Next we define our ClockModel as a Singleton
injector.mapSingleton(ClockModel);this means that we will have only one instance of the ClockModel class through all the execution of our application.
We should also notice that we are not creating manually a new instance of the ClockModel using the new keyword and we also haven’t structured the ClockModel class to be a Singleton, we leave RobotLegs to handle it. RobotLegs is clever enough to automatically instantiate the ClockModel class the first time that an Actor asks for it and then it keeps a copy of it to be able to inject it to the other Actors when they need it.
In the clock demo application the ClockModel will be instantiated when the StartClock command is executed, why?
Let’s take a look at the code for the StartClock command:
public class StartClock extends Command { [Inject] public var clockModel:ClockModel; override public function execute():void { clockModel.start(); } }I bet you have noticed the Metatag [Inject] just before the declaration of the class member clockModel. That is what RobotLegs is looking for. What RobotLegs does (by using SwiftSuspender) is recognizing that this command wants to use an instance of the ClockModel and so it will check into its own mapping tables to find out first, the type of mapping and second, what it needs to inject into that variable.
Depending on the type of mapping RobotLegs will act in different ways. In our case the mapping is a mapSingleton so what RobotLegs is going to do is check if it already has got an instance of the ClockModel class, if not (that is our case) create a new instance and injects it into the command variable.
So that is how the ClockModel instance is created by RobotLegs.
Next a little trick to be able to map a Mediator to the main application Sprite.
This is useful when you wish to have control on the main application Sprite in the same way as all the other Views using RobotLegs.
What you do is mapping the main application class to a mediator and then force the creation of the mediator by calling the createMediator method passing the contextView which is the instance of the main application class.
Now ClockAppMediator can control the main application Sprite.
I did this in the clock demo because I needed to listen to the Event.RESIZE event to then be able to re-align the clock Views on the stage while resizing, and I thought that they were responsibilities of the main application class.
Ok now we have the model, we need to display the model data. What we do is creating the Views.
AnalogClock and DigitalClock are the two views we want to use, they extend the Sprite class and implement the Clock interface (we’ll look at this later on).
As for RobotLegs each view needs a Mediator and here are the Mediator responsibilities so we can understand why they are needed:
So the mediators are the point of connection between views and all the other RobotLegs Actors.
When are they instantiated in our application?
When the AddClocks command is executed. Let’s see the AddClocks command in detail:
public class AddClocks extends Command { override public function execute():void { contextView.addChild(new AnalogClock()); contextView.addChild(new DigitalClock()); } }You can see that the two views are created and added to the contextView which is the main DisplayObjectContainer created by RobotLegs. In this case, because already mapped, RobotLegs will automatically create the Mediators for each View and also inject in each Mediator a reference of the View itself.
How? Let’s have a look at the ClockMediator Class.
public class ClockMediator extends Mediator { [Inject] public var clockModel:ClockModel; [Inject] public var clockView:Clock; public function ClockMediator() { } ...This is just part of the class but it’s where we can find how RobotLegs knows what to inject into the Mediator when created.
In this case RobotLegs will inject the ClockModel reference (that is a Singleton and already instantiated) and the relative View instance.
From now on the Mediator will have access to both Model and View and it will be able to mediate between them.
That’s it we can now let RobotLegs execute its startup procedure:
One thing I haven’t explained above is how the views get updated. To find out we need to look at both ClockModel and ClockMediator.
ClockModel:
public class ClockModel extends Actor { private var clockTimer:Timer; public function ClockModel() { super(); createTime(); createTimer(); } private function createTime():void { } private function createTimer():void { clockTimer = new Timer(1000); clockTimer.addEventListener(TimerEvent.TIMER, onClockTimer); } private function onClockTimer(event:TimerEvent):void { dispatch(new ClockEvent(ClockEvent.TICK, new Date())); } public function start():void { clockTimer.start(); } public function get time():Date { return new Date(); } }We can see that the ClockModel class has a Timer object in it, and every second the ClockModel dispatches a ClockEvent.TICK, so our views need to be updated every time the event is fired.
This is a responsibility of the ClockMediator:
public class ClockMediator extends Mediator { [Inject] public var clockModel:ClockModel; [Inject] public var clockView:Clock; public function ClockMediator() { } override public function onRegister():void { super.onRegister(); eventMap.mapListener(eventDispatcher, ClockEvent.TICK, onClockTick); eventMap.mapListener(clockView, Event.ADDED_TO_STAGE, onViewAddedToStage); } private function onViewAddedToStage(event:Event):void { updateView(clockModel.time); } private function updateView(newTime:Date):void { clockView.time = newTime; } private function onClockTick(event:ClockEvent):void { var newTime:Date = event.time; updateView(newTime); } }In the onRegister method we map a listener to the ClockEvent.TICK so every time the event is fired the mediator will update the view.
We can notice one of the advantages of using the MVC architectural pattern, the model is not tightly coupled with the views, business logic is separate from the view representation.
Another aspect that I like about RobotLegs ( and also PureMVC ) is that it almost forces you to separate responsibilities. This could lead to a growing number of classes but I can confirm that having a lot of small classes with specific responsibilities is better than having a big class that does everything. It is more flexible, scalable and maintainable.
So what are the advantages of using RobotLegs (or shall we say the MVC pattern)?
Let’s go back to the beginning where we set the target for the Clock Application. We wanted to display the time in different ways. So far we’ve implemented two ways Analog and Digital, what if we want to add another view?
We will just need to create a new View which implements the Clock interface and then map it to the ClockMediator in the startup method of the ClockContext class.
Then we also need to change the AddClocks command so that we add the new View to the main container.
That’s it!
You can notice that we have just added our new view and changed a command, we haven’t touched the model at all.
Another scenario : We want to display the time of a different time zone, what we do is changing just the ClockModel, nothing else.
Hope this example helps you understand a bit more about RobotLegs and the MVC architectural pattern so if you have any thoughts, questions or if you’ve spotted an error please feel free to leave a message.
Vizio