aodz

FrameworkQuest 2008 Part 5: Mate, the Pure MXML Framework

Posted on: January 16, 2009


FrameworkQuest Part 5 by Tony Hillerson
Find the original post here

FrameworkQuest 2008: Introduction
FrameworkQuest 2008 Part 2: Get Control with Cairngorm
FrameworkQuest 2008 Part 3: Agnostic Views with PureMVC
FrameworkQuest 2008 Part 4: IoC With Swiz
FrameworkQuest 2008 Part 5: Mate, the Pure MXML Framework
FrameworkQuest 2008 Part 6: The Exciting Conclusion

Let’s get this out of the way first thing. It’s Mah-tay, not
M-eight. Like the drink, the creators of Mate, Nahuel Faronda and
Laura Arguello
, come from Argentina. If you’ve never tried Mate (the
drink), you should – it’s tasty. If you’ve never tried Mate

(the framework), well, that’s tasty, too, and you’re about to dig into a big
bowl full. Sorry about that mixed metaphor there.

Mate is design to take advantage of MXML and regular old Flash
events dispatched the regular way, not through the framework like Cairngorm or
Swiz (although Swiz is open to regular event dispatching if you set it up
yourself). In that way it’s like PureMVC. But Mate uses the fact that part of
the framework is defined right at Application level to make the event-driven
part of the framework very unobtrusive and easy.

Since it’s very unobtrusively event based (you’ll see what I mean
in a bit) it allows you to make a very componentized application easily, and
although of course you can use the classes from the framework in ActionScript
form, you’ll be surprised at how much you can do right in MXML.

Let’s look at one of those green box things again. The Delegate is yellow to
show that it’s optional.

So when a user interacts with the view, and event is fired. The EventMap, declared on
the root application receives all events dispatched anywhere in the view as
long as the bubbles
property of the event is set to true. So the basic way of acting on some user
input is to dispatch a custom event with the bubbles property set to true. This is
how Mate is so unobtrusive. You don’t have to define event listeners all over
the place, just define some code in the EventMap to catch certain types of
events. The EventMap
takes care of calling the service in simple situations, but it could delegate
the service call to a delegate as well.

The EventMap
could also fire off a command, Cairngorm style, if you
like that way of doing things better. Mate is a very flexible framework. In
fact, there are a lot more parts to Mate than are listed here and any of them
could be used to do things a different way or to deal with exceptions. Mate’s
documentation is particularly good and easy to use compared to the other
frameworks, so have a look at it if you want.

To get data into the view, Mate either defines an IoC style Injector or simply
dispatches an event with an EventAnnouncer
and the view can use Mate’s Listener
tag to be notified of these events. We’ll see both ways of doing things.
Storing data in the model is delegated to objects that most of the examples
call Managers.
Some examples use a Manager
to actually do service interaction. Again that’s up to you and how pure you
want the model to be.

Ok, let’s start looking into how I did this application the Mate
way.

Twitter Through A Bomba

The first Mate specific code in our app is on the root
application.

twitteria_mate/src/twitteria_mate.mxml #21

<maps:MainEventMap />

The EventMap
is central to any Mate application, so it’s defined early. Note that although
we only have one, you can have as many as you want, so you can break things up
as clean as you want them.

Each application defines its own EventMap, and ours is imaginatively
called MainEventMap.
There’s not a lot more to see on the application, so let’s look at logging in.

Logging In

Once again, hitting enter in the password field kicks off the
login process. It calls the login
method on LoginView.

twitteria_mate/src/com/insideria/twitteria/view/LoginView.mxml
#10-13 (formatted)

public function login():void {
      var le:LoginEvent = new LoginEvent(
           usernameText.text, passwordText.text

      ); 
      dispatchEvent(le);
}

We dispatch a LoginEvent
and send along the username and password. Nothing framework specific. Let’s
look at the LoginEvent.

twitteria_mate/src/com/insideria/twitteria/events/LoginEvent.as
#7-16 (formatted)

public static const LOG_IN:String = "login";


public var username:String;
public var password:String;

public function LoginEvent(username:String, password:String) {
      super(LOG_IN, true, false);
      this.username = username;
      this.password = password;
}

First, we keep a constant on the event to make sure the type of
the event is clear. We also have a place for the username and password payload. The super call is
important. The arguments are ‘type’, ‘bubbles’, and ‘cancelable’. The type is
our constant, and bubbles is set to true. That’s important because when an
event bubbles it moves all the way to the top of the display object tree and
anything in the tree can listen for it. The EventMap ultimately listens for this
event.

twitteria_mate/src/com/insideria/twitteria/maps/MainEventMap.mxml
#13-16 (formatted)

<EventHandlers type="{LoginEvent.LOG_IN}" debug="true">

     <ObjectBuilder
          generator="{TwitterDelegate}"
          constructorArguments="{[
               event.username, event.password, scope.dispatcher
          ]}" />
     <MethodInvoker
          generator="{TwitterDelegate}"
          method="loadTimeline" />
</EventHandlers>

Wow. There’s a lot going on here, so let’s break it down. The EventHandlers tag
defines the actions to take for a certain type of event, designated in the type property. This
corresponds to the constant in our LoginEvent, so this is the event handler for when that
event bubbles up.

When that event gets caught, the first tag takes over. The ObjectBuilder
tag creates an object of a certain type, which is set in the generator property. That can be either
a fully qualified path as a string, or a class in a binding, like we have. The
default behavior is to create an object of that type and keep a reference to it
indexed by type. That means that any another object of that type is requested,
the cached object will be returned. This is how Mate deals with the problem
that Cairngorm deals with using singletons, that of keeping an instance of an
object easy to get to.

The constructorArguments
are, of course, how you pass in arguments to the class’ constructor. Here we
pass in, from the incoming event, the username, password, and from the scope property of the

EventMap, a dispatcher. Hopefully
the event properties are clear enough to you. The dispatcher thing needs to be
cleared up a bit though, I bet. What we’re going to do, since we don’t have a
standard service to call, like a RemoteObject, WebService, or HTTPService, which all have invokers in Mate, is to have a delegate that
dispatches events when things happen. To make that work with any Mate Listeners, which
we’ll see in a bit, we need to dispatch the events through Mate. This dispatcher passed
into the TwitterDelegate’s

constructor lets us do that.

Next, we use a MethodInvoker
tag to invoke a method on the TwitterDelegate,
namely loadTimeline.
The MethodInvoker
uses the same generator style. Since the defaults are in place on the ObjectBuilder, the
object that was built there will be reused here. In fact, We didn’t even really
need to use the ObjectBuilder,
because the generator in MethodInvoker

would have cached the class too. That’s the default behavior of most of the
tags used in the EventMap.
Why did I use the ObjectBuilder
then? Just to show it could be done and to make it explicit. Look, I’m trying
to teach here.

That was a lot of explanation for two or three tags, so let’s say
it in plain English. When the EventMap
gets the LoginEvent,
it builds a TwitterDelegate

and caches the instance for whenever another TwitterDelegate is requested. Then we
invoke loadTimeline
on a TwitterDelegate,
which uses the cached instance. Let’s see what happens in the delegate.

Loading The Timeline

Just like before, we decide on using the dummyData or not, and possibly call
the Twitter service.

twitteria_mate/src/com/insideria/twitteria/business/TwitterDelegate.as
#33-42 (formatted)

public function loadTimeline():void {
      if (useDummyData) {
            var te:TwitterEvent = new TwitterEvent(
                 TwitterEvent.ON_FRIENDS_TIMELINE_RESULT
            );
            te.data = getDummyData();
            friendsTimelineLoaded(te);
       } else {
            twitterService.loadFriendsTimeline(username);
       }
}

And either way, the callback is executed.

twitteria_mate/src/com/insideria/twitteria/business/TwitterDelegate.as
#53-56 (formatted)

private function friendsTimelineLoaded(te:TwitterEvent):void {
      var e:TimelineReceivedEvent = 
           new TimelineReceivedEvent(te.data as Array);
      dispatcher.dispatchEvent(e);
}

This time it’s different, though, and we get together a TimelineReceivedEvent
with the array of tweets and dispatch it through the dispatcher we got from the
MainEventMap
when the delegate was constructed.

The MainEventMap

is listening for that kind of event:

twitteria_mate/src/com/insideria/twitteria/maps/MainEventMap.mxml
#18-21 (formatted)

<EventHandlers 
     type="{TimelineReceivedEvent.TIMELINE_RECEIVED}"
     debug="true">

     <MethodInvoker
          generator="{TwitterManager}"
          method="setCurrentTweets"
          arguments="{[event.tweets]}" />
     <EventAnnouncer
          generator="{ViewStateEvent}" 
          type="{ViewStateEvent.SHOW_MAIN_VIEW}"
          bubbles="true" />

</EventHandlers>

When it gets it, it invokes setCurrentTweets on a generated TwitterManager and
passes the tweets we set on the event. It then uses an EventAnnouncer
to fire a ViewStateEvent

of type ViewStateEvent.SHOW_MAIN_VIEW.
Let’s take those one at a time.

The TwitterManager
is our model-type object, following what I take to be a Mate naming convention.
It’s simple enough.

twitteria_mate/src/com/insideria/twitteria/business/TwitterManager.as
#5-12 (formatted)

public class TwitterManager {
      [Bindable]
      public var currentTweets:ArrayCollection;
     
      public function setCurrentTweets(tweets:Array):void {
            currentTweets = new ArrayCollection(tweets);
       }

It just has a Bindable collection of tweets and a way to set them. Now
that they’re set, how do they get to the view? A PropertyInjector, with the help of Flex
binding.

twitteria_mate/src/com/insideria/twitteria/maps/MainEventMap.mxml
#31-33 (formatted)

<Injectors target="{MainView}">
     <PropertyInjector
          source="{TwitterManager}"
          sourceKey="currentTweets"
          targetKey="currentTweets" />

</Injectors>

This is another very Mate way of doing things. This is saying
that Mate should bind the currentTweets
property of any cached TwitterManager
into the cached MainView
instance’s currentTweets.
Hold on, when did a MainView

get cached? Well, as a service to the user, Mate listens for the event from any
view (I believe the creationComplete
event) just like it does for any other user defined bubbling event, and then
caches a reference to that view. That way the EventMap has a way to communicate with
the view of any type. Sneaky, eh? I thought so. Now whenever the currentTweets on our
manager changes, that view will be updated. Now we have the data getting to the
right view, but how do we get the ViewStack on the application onto the right index?

That second tag, the EventAnnouncer fires off a ViewStateEvent.

twitteria_mate/src/com/insideria/twitteria/events/ViewStateEvent.as
#7-11 (formatted)

public static const SHOW_MAIN_VIEW:String = "showMainView";

public function ViewStateEvent(
                               type:String,
                               bubbles:Boolean=true,
                               cancelable:Boolean=false) {
      super(type, bubbles, cancelable);
}

Since we’re using the EventAnnouncer to fire this off, it needs the standard
event constructor. Also, we could have lots of view state constants to use for
different view state events since Flash events are unique by sort of a weird
mix of class and type property. So where does this event go? Well, if we look
back on the application, we’ll see.

 

twitteria_mate/src/twitteria_mate.mxml #23 (formatted)

<mate:Listener
     type="{ViewStateEvent.SHOW_MAIN_VIEW}"
     method="showMainView" />

Here’s a Listener

tag that listens for just that event type. When it gets it, it calls showMainView.

twitteria_mate/src/twitteria_mate.mxml #7-12

public const LOGIN_VIEW:int    = 0;

public const MAIN_VIEW:int     = 1;

private function showMainView(e:Event):void {
      mainViewStack.selectedIndex = MAIN_VIEW;
}

That method sets the view stack to where it should be. Now we
have the MainView
showing in the ViewStack
and right data in the list in MainView.
Let’s have a look at setting status now.

Setting Status

As you probably can guess, we set status by firing off an event.
Here’s where we do it:

twitteria_mate/src/com/insideria/twitteria/view/MainView.mxml
#12-16

private function setStatus():void {
      var e:SetStatusEvent = new SetStatusEvent(statusText.text);
      dispatchEvent(e);
      statusText.clear();
}

And here’s where it ends up:

twitteria_mate/src/com/insideria/twitteria/maps/MainEventMap.mxml
#23-25 (formatted)

<EventHandlers type="{SetStatusEvent.SET_STATUS}" debug="true">

     <MethodInvoker
          generator="{TwitterDelegate}"
          method="setStatus"
          arguments="{[event.statusText]}" />
</EventHandlers>

We call setStatus
on the cached TwitterDelegate,
passing in the statusText
from the incoming event.

twitteria_mate/src/com/insideria/twitteria/business/TwitterDelegate.as
#58-61

private function statusSet(te:TwitterEvent):void {
      var e:StatusSetEvent = new StatusSetEvent();
      dispatcher.dispatchEvent(e);
}

When the delegate is done, it dispatches a StatusSetEvent through
its dispatcher.

 

twitteria_mate/src/com/insideria/twitteria/maps/MainEventMap.mxml
#27-29 (formatted)

<EventHandlers type="{StatusSetEvent.STATUS_SET}" debug="true">

     <MethodInvoker
          generator="{TwitterDelegate}"
          method="loadTimeline" />
</EventHandlers>

Back in the EventMap,
it catches that event and reloads by calling back to the delegate, which kicks
off that whole chain again.

Next Up

Mate’s sort of a different beast from the other frameworks. The EventMap approach is
novel, as is the class caching. Once you see how it works, it’s a lot of fun to
use, though.

Now we’ve built our application using four different Flex
frameworks. Again, although it wasn’t an exhaustive look at each framework or
its capabilities, and since our use cases may have been a little out of the
ordinary especially around the delegate area, I hope that this has at least
shown you how it feels to use these frameworks in a day-to-day setting.

Next up, we’re going to get into the opinion section of the app,
where I tell you how I think each framework stacks up against the others, which
one I’d like to use from now on, and which one I think renders the most
Programmer Joy.

Read more from
Tony Hillerson
.

Advertisements
Tags:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

I have moved to a different location

check out my new home Flexout

calendar

January 2009
M T W T F S S
« Dec   Feb »
 1234
567891011
12131415161718
19202122232425
262728293031  

Blog Stat

  • 83,725 Hop's so far!!!

follow me

Archives

Linkedin Blogger Twitter Youtube Orkut

Top Clicks

  • None

latest flickr photos

top rated

%d bloggers like this: