Flex widget communication PoC

May 29
2009

Problem : How do you get several distinct Flex widgets on a page to communicate?

By distinct here I mean that each widget is a separate embedded SWF file, i.e. they don’t share the same Application.

There are actually several ways to do this, and an appropriate choice really depends on the kind of data you want to share and when. What I needed was real-time communication; say I have one widget that searches for a particular resource (in my case they’re bonds), when the user selects a resource, that widget should propagate the selection to all the others on the page. It was also a requirement that the number and identity of the widgets on the page be an unknown – i.e. I can’t assume that there will always be exactly three widgets called Fred, Bob and Jane.

Not being a Flex expert, my first thought was to use a SharedObject. This seemed like a good idea since apparently they “offer real-time data sharing between multiple client SWF files”, which is exactly what I want. However, this is only possible if you’re using Flash Media Server. I don’t really need that round-trip to the server each time and I don’t need to communicate between multiple clients, just among SWF files on the same page at a single client. I also don’t have Flash Media Server. I did toy around briefly with a polling solution using local SharedObjects though. The server SWF would contain something like this :

public function syncSharedObject(sharedText:String):void
{
    var so:SharedObject = SharedObject.getLocal("test", "/", false);
    so.data.sharedText= sharedText;
    so.flush();
}

And the client SWF would contain code to poll the SharedObject periodically to check for updates (I’m not going to show the boilerplate code that sets up the Timer instance):

public function syncSharedText(event:TimerEvent):void
{
    var so:SharedObject = SharedObject.getLocal("test", "/", false);
    sharedText = so.data.sharedText;
}

Simple! But also fairly braindead. This is a pull architecture – the clients aren’t notified when the data has changed, so they have to keep looking at it (say every half second), which creates some annoying overhead – each widget interested in “sharedText” would have to poll the SharedObject and that could be a lot of widgets looking at one piece of data. Of course, this gets worse if we need to pass around lots of different pieces of data!

So, back to the drawing board and a little more reading, after which I discovered LocalConnection. This seems to do pretty much everything I need, but it’s definitely more complex to get up and running with. What I want is one widget to act as a server and notify all the other widgets about changes to relevant data, however I can’t designate a specific widget as the server because I don’t know if it will always be present. A simple solution would be to let the first widget to load grab the publisher/server functionality and all subsequently loaded widgets would then be subscribers/clients (I decided to call the class MessageManager, and, since it will need to raise events, it extends EventDispatcher) :

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//constructor (I'm not going to write out all the class definition code)
public function MessageManager(target:IEventDispatcher=null)
{
    //Generate a locally unique ID.
    this.subscriberID= UIDUtil.createUID();
 
    try
    {
        //First we try to connect as the server.
        conn = new LocalConnection();
        conn.connect("Server");
        conn.client = this;
        isServer = true;
 
        //initialise the subscriber cache.
        subscribers = new Object();
    }
    catch (e:Error)
    {
        //The server probably already exists; register ourselves with it.
        isServer = false;
        conn = new LocalConnection();
        conn.connect(subscriberID);
        conn.client = this;
        conn.send("Server", "registerSubscriber", this.subscriberID);
    }
 
    super(target);
}
 
public function registerSubscriber(subscriberID:String):void
{
    if (!subscribers[subscriberID])
         subscribers[subscriberID] = true;
}

There are a fair few assumptions in this code (there’s no real error handling, for a start), but it works well enough for a PoC. It may seem a little confusing to use the same class for both publisher and subscriber interfaces, and it would be entirely feasible to separate them out, but I didn’t consider that necessary for such a small scale test.

With the publisher and subscribers loaded and registered, I now need to be able to send a message. I created a MessageManagerEvent class which extends Event with an additional data property, this contains the “message” to be passed around (a fairly common pattern – the Flex store sample application uses something similar but calls it ObjectDataEvent). For a widget to then update all other widgets, it just needs to create a MessageManagerEvent and call the MessageManager.sendMessage method. sendMessage determines whether the current instance of MessageManager is the server or a subscriber and either sends a single message to notify the server or iterates over the subscribers collection notifying each one in turn. I created a simple application to demonstrate this in action and included two of them below (you should be able to view source on either) :

Just enter some text into either box and you should see it copied across to the other application.

If you refresh the page a few times, you may notice the “SERVER” and “SUBSCRIBER” labels flip back and forth between the widgets, depending on which one loads first. If you open a new copy of this entire page, the new instances should both be saying “SUBSCRIBER” (assuming you keep this page open). Even more interesting is that if you open a copy of this page in another browser entirely, you may find that those say “SUBSCRIBER” as well, and that text is propagated to them from the original browser instance! (I’ve noticed this works between FireFox and IE so far, YMMV, of course).

A few points to note :

  • You can use more complex objects as messages, but each widget must have a reference to that type compiled in, otherwise it won’t deserialise correctly.
  • Any type used as a message must have a default constructor, or at least a constructor with default parameters.
  • This is far from being a usable implementation, since it doesn’t account for the possibility of the server or any subscriber dying. Ideally there would be a mechanism for a subscriber to take over the server role if the server is removed, though this would probably require use of a SharedObject to persist the subscriber list.

Update

What I’ve done here was for my benefit really – a learning exercise. What Blitz Agency has done here is something on another level altogether. Under the hood it’s all still LocalConnection based though.

In the beginning, there was WordPress

May 28
2009

I suppose the first problem I want to recount the solution of is that of getting this site up and running. That means going from nothing at all to having an account with a budget hosting company, my own domain and a WordPress installation through which I can deliver my ramblings.

If you’ve never done this kind of thing before, it can seem quite daunting. After all, there are hundreds (thousands?) of hosting companies and it’s easy to become paralysed by choice. My own advice here is to either pick a local company that has prices you can live with, or solicit recommendations from friends. If you have the time, by all means do lots of research, but if you’re looking for a budget host don’t expect to be much wiser after a few hours of hunting around on the web. You’ll probably end up paying a few pounds a month for the hosting service and around £10 a year for a .com address (a .co.uk is even cheaper – the really expensive top level domain seems to be .it at the moment, at around £50-60 per year).

Remember, you don’t have to be tied to the same hosting company forever, and with hosting so cheap at the moment you can probably afford to get it wrong, or at least, not 100% perfect. There will always be something that annoys you about the company you decide to go with, and if you accept that that’s going to be the case you can be a lot more Zen about the whole process.

I ended up going with 34SP.com, not because they’re the best, but because I’ve used them before and their prices seem, if not reasonable, then at least bearable. Setting up an account with them was as easy as buying from Amazon – it’s certainly not something to be afraid of.

With domain and hosting space acquired, the next step was to install WordPress. This was almost trivially easy because 34SP actually provide an installation script to do it for you! You may find that many hosting companies will offer this kind of service (installing WordPress seems to be a fairly common first step for new web administrators).

WordPress themes go here.

WordPress themes go here.

Finally, I needed to pick a WordPress theme that was slightly more interesting than the Kubrick default. I know this is something I can easily change at any time and I didn’t want to spend hours browsing the WordPress themes gallery, so I had a very quick look and settled upon Streamline for now (of course this may have changed by the time anyone actually reads this). Installation meant connecting to my site via ftp for the first time (I use FireFTP) and simply copying the unzipped theme folder into wp-content/themes. Activating the theme was done via the wordpress dashboard. Easy!

So, now I have a blog and a website to play with. Hopefully my next post will be a little more technical, but then not all solutions are technical in nature. Sometimes it’s just enough to know that something can be done without giving the average person a headache.

Visit Our Friends!

A few highly recommended friends...

Archives

All entries, chronologically...

Pages List

General info about this blog...