Thursday, May 28, 2009

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 2

This is a continuation of TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 1, in which I decided to complete a number of technical exercises by building a Twitter desktop client using the Twitter API, Adobe Air and the Mate Framework. 

If you recall, last time I was able to successfully make a call to the Twitter public data feed that returns the last 20 public tweets, and display them in a list in my client. It looked like this:




So, clearly I've got a ways to go, but certainly this represents a major element of the development; get the data, parse it, bind it to a list with the UI elements to properly display the data. Keep reading; the app doesn't look like this anymore.

The next step was to clean up the UI a bit, which is what we'll look at here. Although not a programmer as far as I know, iJustine, an internet/lifestyle tweeter and blogger of some notoriety, unknowingly gave me a suggestion for how to proceed. She said that she couldn't change the background color of her tweet display; I assume that if she wanted this feature, it would probably be a popular one, so I decided to implement a way to skin my Twitter client at a rudimentary level. 

And I must say, Mate made it pretty easy to do. I think any framework would have, being as the task of reading in config data is the same as reading in any other kind of XML data, and I had already set up a call/receive pipe for the public tweet XML, so ideally I should just be able to use the same exact technique, and that's exactly how it panned out. 

In the last article, I showed the fragment of Mate code (which is just MXML) that retrieved the public tweet feed. The code below does the same exact thing, except it hits a relative file, config.xml, instead of a remote service. 

The Mate formula for hitting data and storing it seems to be this:

- Create your Event class (in this case, Event_Config). This is a standard Flex/Flash event, nothing fancy. It should have a static constant (at least one, though it can have several) with the name/type of event you want to dispatch (which is always a best practice for events not matter what environment you're in). 
- Create a Manager class that will be passed arguments when the event is handled by the EventMap. This means creating at least one public method on the class. Interesting that none of the examples I have seen ever suggest exposing these public methods via an interface...which is something I'll comment on later. I used Manager_Config.
- Create a Model class, I like to use singletons, to hold the elements the Manager parses out.
- Tie the Event, and it's handler, to the Manager, via the EventMap. 
- Dispatch your event as needed, remembering that in Mate, events have to bubble to the EventMap, which initially, will be located in the top-level MXML file. This means that you can either only dispatch from an object that participates in the app-level DisplayList, or by using the GlobalEventDispatcher workaround detailed in my last article. 

The code fragment that does the above looks like this:



<mate:EventHandlers type="{Event_Config.GET_CONFIG}" debug="true">
<mate:HTTPServiceInvoker url="xml/config.xml" resultFormat="xml">
<mate:resultHandlers>
<mate:MethodInvoker generator="{Manager_Config}" method="storeConfig" arguments="{resultObject}" />
</mate:resultHandlers>
</mate:HTTPServiceInvoker>
</mate:EventHandlers>



So, when the app starts, I want to load the config.xml file, which I do like this:

- In creationComplete of TcozTwitter_AIR, I dispatch an instance of Event_Config, using type Event_Config.GET_CONFIG. 
- This bubbles to the EventMap handler MXML tag, which makes the call to the HTTPService, receives the result, and directs it to the Manager_Config class public method, storeConfigOptions.
- That method takes the result argument, parses the XML, stores the elements on the associated properties in Model_Config, which exposes them for use throughout the app. 
- At the appropriate times, the UI elements, like Tweet backgrounds, apply their colors as style elements. 

iJustine, there ya go. Again, more or less the same exact idea as grabbing tweets, or any data it would seem. 

Some observations on this flow:

This is the way the tutorials, and even more advanced samples I've seen, prescribe retrieving service data. Typically though, I would not use the HTTPService MXML tag (or any such MXML based mechanism for that matter), I'd forward the handling to a class using the Command pattern. I've read some ways to do this in Mate, but it seems that it's not the common practice; using the EventMap handler as the Command, and distributing the management of the result to Managers, is the norm. For basic things, this might be ok, but what if you have a complex command of some kind that runs several service calls? The MXML could get very bulky, or you'd need multiple handlers, which would seem to make atomic operations difficult to manage. In fact, I think that in an app of any size, EventMaps could get bulky fast, which would cause you to start thinking of your app in terms of layers of EventMaps. Conceptually, perhaps this isn't that much different than thinking of your app in terms of layers of Mediators in PureMVC, but plain old code looks a lot leaner 'n meaner to me than all those MXML carats, quotes, equal signs, and so on. 

Based on that, I'll probably only use an EventMap handler tag to initiate a command, like calling a service, if there is only ONE simple command and result. Anything more and I will broker it to a Command class, which fortunately, I know how to make dispatch events now (same as any non-view class, use GlobalEventDispatcher). I know Managers could be thought of as Commands, but they're really not, see below. 

Another observation which I touched on before; use of MXML tags instead of instances of classes lets developers avoid thinking of factoring their class hierarchies and exposing their public members using interfaces. I understand that the classes that back the MXML tags are well factored in this manner, but for example, in PureMVC, part of it is implementing the Command pattern as the "C" in "MVC" (control). As you may know if you've gotten this far, the Command pattern uses an interface to expose "execute". If you use a Template pattern (so you create a base class that implements the interface and you extend that base class whenever you create a specific kind of command), you've just made all your commands polymorphic, which lends to things like "undo", command stacks and chaining, etc. Mate doesn't seem to have this concept built in. 

Good thing, bad thing? I don't know. To me, one of the points of a framework is to prescribe patterns of development for common application tasks, like executing logic. If you use Cairngorm or PureMVC, all I need to know is that a developer understands the framework, and I know that when I say "call a service, handle the data, store it", that the developer--in the case of PureMVC--will dispatch an event to a Mediator, which will send a Command Notification to the Facade, which will execute the a Command class, which will make the service call and handle the result, then broker that result to to a Proxy class, which will parse the data and store it on the Model, which makes it available to the application. 

It may sound verbose, but it's explicit and actually saves a lot of time; I KNOW how the developer will perform the task, and if you're managing a bunch of them, that's a GREAT thing. Using Mate, it would seem that I'd have to lay out the flows myself and communicate them to the team as standards, and make sure they were doing it. With a team of PureMVC junkies, we may quibble about the best way to cut up an application with mediators, or the best way to represent a Model via a Proxy, but otherwise things like views calling views or views talking directly to models will never happen; if it does, the fix is to educate the developer on the prescribed mechanisms of the framework. 

Anyway, enough of that. The bottom line is, you make edits to an XML file, restart your app, and voila, there are your colors, nice gradients and all that. Note that an XML file is not how I intend to keep this; settings is a great opportunity to take advantage of Adobe Air local storage. But for now, until I establish a base set of requirements for preferences and settings, it's easiest to just keep it in something abstract and lightweight, as opposed to building out the settings UI now, knowing that it will just change drastically several times before I have a locked feature set. 

One other thing I took advantage of: Air's ability to have the app resize like a desktop app, and reflow the layout. This is a great thing IMHO; if you resize the Twitter HTML page, the tweets don't reflow to take up the entire width, they stay in one column. My client reflows the tweets to take advantage of the entire space, letting you see more tweets without scrolling. 

Next step: incorporating the metadata associated with a user, and getting that message field populated. 

Screenshots of the latest client below, showing the application of the config.xml, and the resize-reflow. As always, thanks for visiting.







1 comment:

  1. The killer Twitter app (for me, anyway), would be one that had multiple, customizable columns: you could load each column with a different account (I have a couple), or you could use a column for a search. I like to monitor a live search for "actionscript."

    ReplyDelete