About how to reuse a simple control flow facility for Android activities-submitted by Fabrizio G on the android Interface Component

Source: Internet
Author: User

In bluebill mobile for Android (BTW, I have published the first version to the Android Market) I 've had to face with an internal reuse problem. consider the following diwing, which depicts a couple of possible "screen" flows that the user may navigate:

In Android, every "screen" is called activity. the application starts with the observationsactivity, which shows the list of recorded observations. by pushing a button, the user can insert a new one. this task is accomplished by a wizard-like flow described by the upper sequence in the digoal:

    1. eventually pick a bird species from a history list (containing the most recent picks) (picktaxonactivity).
    2. Alternatively, the user can push a button and get to a new screen where it is possible to browse a taxonomy and drill down to a single species (taxonbrowseractivity).
    3. then the number of observed birds and their gender is entered (countandgenderactivity ). by pressing an "add more" button, the user might cycle and loop back to entering a new species.
    4. instead, by pressing an "OK" button, a final picklocationactivity allows to enter the location of the observation.
    5. At the end, the user returns to the observationsactivity.

In a second function, the user might want to recall a fact sheet of a bird species, with information, media (photos and sounds), etc. it makes sense to reuse the same two activities (picktaxonactivity and taxonbrowseractivity) and, after the selection has been done, to get to a factsheetactivity:

    1. Eventually pick a bird species from a history list (containing the most recent picks) (picktaxonactivity ).
    2. Alternatively, the user can push a button and get to a new screen where it is possible to browse a taxonomy and drill down to a single species (taxonbrowseractivity ).
    3. Then the factsheetactivity is rendered.

 

How does one navigate through activities in Android? By means of an asynchronous message-passing facility called "intent ". basically, one activity creates and sends a message to the runtime, which reacts by bringing on the screen the recipient activity of the message, that gets activated.

Messages can be based on a sort of "Publish and subscribe" pattern (they carry a "topic" and the proper activity is found as it declared to be competent about the topic in the application manifest):

 
Intent intent = new intent ("topic"); // eventually put extra information into the intentstartactivity (intent );

Alternatively it is possible to explicitly specify the recipient by referring its class (in this case we have a "Point to Point" messaging system ):

Intent intent = new intent (); intent. setclass (..., nextactivity. Class); // eventually put extra information into the intentstartactivity (intent );

A special kind of message is generated by calling the finish () method, which notifies that an activity terminated its task, so the control is returned to the sender of the message.

As a plus, Android keeps track of the flow and implements a stack of the recently visited activities, so the "back" button usually works automatically without needing further code; the "finish" message flushes the stack up to the caller point.

I'm a big fan of the "Publish and subscribe" pattern because it does a great job in decoupling the various part of a design. in Android, the mechanic is very powerful because the varous activities needn't to be part of the same application: It's very easy to have multiple applications to cooperate. for instance, sending an intent with a pre-defined topic can bring up the email client, or the phone contact list, etc.

Unfortunately, often you need the "Point to Point" variant of messaging when you operate inside an application as you require a specific sequences of activities, as in my introductory example.

now, the "Point to Point" pattern is very coupling because the originator needs to know the recipient. in other words, picktaxonactivity and taxonbrowseractivity need to know which is the next activity to start: countandgenderactivity (flow #1) or factshetactivity (flow #2 ). if I wanted to reuse them in further scenarios, I wowould have more coupling and complicated code, with picktaxonactivity and taxonbrowseractivity depending on a number of other activities, while it showould be really the opposite. this is a sign of a bad distribution of roles & Responsibilities: Activities shocould only focus on their own task and know nothing of what happens after.

Who shocould be in charge of defining the sequence? A possible candidate cocould be the initial observationsactivity as it knows which command has been invoked by the user, thus it knows the whole sequence of steps to walk through. so, in a first time I thought of an approach where each activity, when it completes, always sends a "finish" message, so it immediately returns to observationsactivity; this class wocould implement the logic for finding the next step and starting the related activity.

Unfortunately, in this way you completely loose the stack-based back button implementation provided by Android, which is a big pitfall. in order to keep it, each activity, when it completes, must keep on sending messages forward.

Self-routing messages

The elegant solution I 've found to work is based onSelf-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 extends strates:

 
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 shoshould be readable enough to understand that it implements the flow #2 in our digoal. to start it, the originating activity cballs:

 
Controlflow. Start (this, taxonfactsheetcontrolflow. Class );

The specified controlflow not only 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 cballs:

 
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 callone 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 Daily 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.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.