December 21, 2014

Gettin' On The (Message) Bus, Part One

The message bus is a tried-and-true model in application development. Whether it is the humble Win32 message loop or full-fledged publish/subscribe message-oriented middleware solution, software components have long been publishing messages that other components receive, either by explicitly checking some message queue or by virtue of the message matching some pattern the receiver subscribed to.

Guess what? The Android system of Intent objects is just a message bus. The principal aim is for the bus to pass around messages related to the system, from media card inserts to requests to perform some action on some piece of content, like a contact. But, the Intent bus can be used by your own activities and other Android components, not only for communicating with Android, but with each other.

In today’s segment of Building ‘Droids, we’ll look subscribing to messages on the bus using an IntentReceiver. Later, we’ll look at sending Intent objects on the bus to be delivered to your receivers, or receivers others might set up.

Activities are set up to receive Intent messages, as defined in AndroidManifest.xml via intent-filter elements. For example, most applications have an activity with an intent-filter set up like this:

[sourcecode language=’xml’]




[/sourcecode]

To receive your own messages, particularly when you only want them at certain times, you will want to use IntentReceiver. Here’s a quick recipe:

First, come up with the name for the Intent you want. This should be distinct from any other Intent name on the device. The easiest way to ensure this is to have it use your application’s Java namespace, such as:

[sourcecode language=’java’]protected static final String PROXIMITY_ALERT = “com.commonsware.tourit.intent.action.PROXIMITY_ALERT”;[/sourcecode]

Next, create an IntentFilter that will look for Intent instances with your supplied name, such as:

[sourcecode language=’java’]protected final IntentFilter proximityLocationIntentFilter = new IntentFilter(PROXIMITY_ALERT);[/sourcecode]

Then, create your own concrete subclass of Android’s IntentReceiver class, implementing onReceiveIntent(). This method receives a Context (e.g., the Activity instance where you created this IntentReceiver) and the Intent message that arrived. It is up to you to do something useful with that message, such as update an activity’s UI (be sure to do this on the UI thread!) or update a SQLite database.

Finally, when you want your IntentReceiver to watch for messages, call registerReceiver() in your Activity or other Context, providing it the IntentReceiver and IntentFilter, such as:

[sourcecode language=’java’]
private ProximityIntentReceiver receiver=new ProximityIntentReceiver();
// …
registerReceiver(receiver, proximityLocationIntentFilter);
[/sourcecode]

Later on, when you no longer need to receive the messages, call unregisterReceiver() with the same IntentReceiver instance you used with registerReceiver().

In our next episode, we’ll see how to set up a component to send messages on the Intent bus.



  • Ramsay Domloge

    So I’m a little confused. I have been messing about with the Android SDK for a couple of weeks now and I am really getting the feeling that although Android might come with a message bus, Intents don’t provide it!

    From my experience, the Handler class is the messaging bus.

    Intents, as far as I can see, are used for decoupling capability from requirement. It makes it simple to start up a web page (for example) without knowing which application/activity should show it (should it be the bundled browser, Opera Mini or Steel?) or how to deal with its lifecycle.

    Essentially, you specify the requirement (show me web page X) and the system supplies an appropriate capability (Steel?).

    On the other hand, Handler’s are useful for enabling messaging between Activities that are started with Intents, since you don’t have a reference to the Activity which is spawned from the Intent. And if your application contains multiple activities and they need to communicate, that’s a pain in the ass…

    Or… perhaps I am *really* not getting the point here…. any thoughts?

    Ramsay

  • http://commonsware.com/Android/ Mark Murphy

    I am not quite certain how Handlers tie into inter-Activity messaging. After all, you don’t need Handlers — there are other ways to force code to execute on the UI thread (e.g., post(), runOnUiThread()).

  • Ramsay Domloge

    From API docs:

    “An intent is an abstract description of an operation to be performed.”

    “A Handler allows you to send and process Message and Runnable objects… (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own”

    My issue is that, once you have started an Activity, using an Intent, you can’t then use Intents to send messages to this Activity. However, you *can* use Handlers and Messages. It’s a bit of a pain, because the Acitivity will need to register its Handler in a static Map which other Activities can use to look it up, but it’s the only solution I have seen so far.

    Don’t get me wrong…. I am hoping I am confused and you will show me way to do this properly! I hate that I *have* to use Intents to start an activity, because this prevents me from getting a reference to the activity. This is necessary, because the framework needs to control the lifecycle of the Activity (I think). Therefore, a messaging bus is required to enable an application with multiple Activities to inter-communicate. I just am not convinced that Intents are *it*. You don’t want to start an Activity just so you can send a message to it… do you?

    Look forward to your insights!

    Ramsay

  • Pingback: benedictional acacatechin atonalistic

  • PM Practice

    Could you provide some basic working example for it?