Fabrizio Giudici is a Senior Java Architect with a long Java experience in the industrial field. He runs Tidalwave, his own consultancy company, and has contributed to Java success stories in a number of fields, including Formula One. Fabrizio often appears as a speaker at international Java conferences such as JavaOne and Devoxx and is member of JUG Milano and the NetBeans Dream Team. Fabrizio is a DZone MVB and is not an employee of DZone and has posted 67 posts at DZone. You can read more from them at their website. View Full User Profile

A Simple Control Flow Facility For Android Activities

05.16.2010
| 13075 views |
  • submit to reddit

Self-routing messages

The elegant solution I've found to work is based on self-routing messages. The idea is to make messages smart enough to know the path they have to follow (it can be a fixed path or one based on rules). This means that when an Activity completes, it delegates the next thing to do to the message itself. Paths can be described by extending the class ControlFlow, as this simple example illustrates:

public class TaxonFactSheetControlFlow extends ControlFlow
{
public TaxonFactSheetControlFlow()
{
startFrom(PickTaxonActivity.class);
when(PickTaxonActivity.class).completes().thenForwardTo(TaxonFactSheetActivity.class);
when(TaxonBrowserActivity.class).completes().thenForwardTo(TaxonFactSheetActivity.class);
}
}

It should be readable enough to understand that it implements the flow #2 in our diagram. To start it, the originating Activity calls:

ControlFlow.start(this, TaxonFactSheetControlFlow.class);

The specified ControlFlow not only calls the first Activity of the sequence, but it also binds itself to the Intent; in this way, it will be possible to retrieve it in the next steps.

Whenever an Activity completes, it calls:

ControlFlow.from(this).toNextStep(intent); // an intent can be used to carry extra information

The originally instantiated ControlFlow is retrieved and invoked to find the next Activity to activate.

In case of rule-based paths, it is possible to pass arguments to be evaluated by the ControlFlow; for instance, CountAndGenderActivity in flow#1 calls one of the two following code fragments reacting to the pressure of the "Ok" and "Add more" buttons:

ControlFlow.from(this).toNextStep();
ControlFlow.from(this).toNextStep(ADD_MORE);

The flow#2 is described by this class:

public class AddObservationControlFlow extends ControlFlow
{
private final Condition addMore = new Condition()
{
public boolean compute (final @Nonnull Object... args)
{
return Arrays.asList(args).contains(CountAndGenderActivity.ADD_MORE);
}
};

public AddObservationControlFlow()
{
startFrom(PickTaxonActivity.class);
when(PickTaxonActivity.class).completes().thenForwardTo(CountAndGenderActivity.class);
when(TaxonBrowserActivity.class).completes().thenForwardTo(CountAndGenderActivity.class);
when(CountAndGenderActivity.class).completesWith(addMore).thenForwardTo(PickTaxonActivity.class);
when(CountAndGenderActivity.class).completesWithout(addMore).thenForwardTo(PickLocationActivity.class);
}
}

As you can see, each transition can be associated with a condition which is function, for instance, of the arguments passed to toNextStep().

This solution is very scalable, as I can reuse existing Activities as many times as I want, by just creating new subclasses of ControlFlow which describe the new sequences to implement.

The code can be checked out from the Mercurial repository at https://kenai.com/hg/bluebill-mobile~android-src, tag dzone20100517.

Published at DZone with permission of Fabrizio Giudici, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Casper Bang replied on Mon, 2010/05/17 - 11:52am

That's a very nice pattern, kind of a fluent-interface version of Struts for Android. :) Does this work with Intent filters, i.e. can an Activity have multiple implementations but let the user pick the preferred one? Say I want to write a "plugin" i.e. TaxonByIdActivity for the hardcore birdwatchers who memorized taxonomy ID's?

Fabrizio Giudici replied on Mon, 2010/05/17 - 1:33pm

I've got some extra code that works with Intents, but it's experimental (and probably unneeded for my current requirements). The pattern was born having in mind to solve the problem of direct coupling, but clearly the smart things it does is decoupling navigation decisions - which could end up in Intents as well.

I'm thinking of a similar things that you described, i.e. the capability of extending blueBill with "plugins" that would be delivered as extra application; for instance, a bunch of media providers, that would provide multiple documents available in the internet (or on the local storage) about a certain bird species. This would work with Intents, of course - both letting the user to pick the desired one, or even calling sequentially all the found things and aggregating the results. I've got a tough week, but I'll probably work on that the next weekend.

Fabrizio Giudici replied on Mon, 2010/05/17 - 1:35pm

PS Another thing that I'll soon study is to try to abstract it from Android. In this way, it could be used e.g. for an implementation in JME or JavaFX Mobile - of course, you don't have Activities in those contexts, but you could as well face with a sequence of "screens".

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.