SyntaxHighlighter

Sunday, August 29, 2010

Using Multiple Activities in Android

I’m new to having to deal with multiple Activities and have learned a lot as I have gone about implementing an app with many Activities.  Lessons Learned:
(1) Don’t try to keep a list of Activities or Activity instances in your main class.  Not only does this waste memory, but when you go to start an Activity you’re not really doing what you think. 
(2) Activities aren’t always around when you need them AKA use Intents.
(3) Use Intents and possibly a little bundling, and the whole thing gets easier.
(4) The Activities constructor is pretty much useless – use onCreate!
I come from a Windows programming background where I didn’t have to worry little things like memory and batteries.  I was used to the old way of doing business where I could create a bunch of screen classes, instantiate them all, and then just show/hide or swap out whatever I wanted depending on the user’s choices.  Yes, life was good.  :)  Then this cool new Android stuff beckoned and off we go…  The old ways won’t work.
The particular problem that I was trying to solve was this.  The app comes up and has 3 screens (Activities, I know I like my windows terms).  The user needs to be able to switch screen to screen.  Simple right?  Easy enough for even a newbie like me to create 3 Activities, create 3 Intents that use those classes, and fire them up right?
    /**
     * onCreate(Bundle savedInstanceState)
     * Called when the activity is first created.
     */

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main); 
        // Create Activity instances
        Activity theActivity1 = new Activity1();
        Activity theActivity2 = new Activity2();
        Activity theActivity3 = new Activity3();

        theActivity1Intent = new Intent(this, Activity1.class);       
        theActivity2Intent = new Intent(this, Activity2.class);
        theActivity3Intent = new Intent(this, Activity3.class);

    }// end onCreate
For the sake of this example we will assume that the user clicks a button that tells the app which screen to display first.  So in the button click we have
startActivity(theActivity1Intent);
and then off we go displaying the first Activity!  What’s wrong with this picture?  A couple of things actually.  (1) we wasted time even calling new on the three Activity classes.  Notice that the Intent is fed in that it is associated with the Activity1 class – not theActivty1 – two very different things.  (2) we really haven’t given ourselves a very good way to pass any needed information into the Activity that might be needed for its display.  (3) we have know way of getting any data back from the Activity, for example, where did the user choose to navigate to next.  Fortunately Android has built in some features that make this easier for us.  Review the updated onCreate
public void onCreate(Bundle savedInstanceState)
{
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main); 

 
   theActivity1Intent = new Intent(this, Activity1.class);
   theActivity1Intent.putExtra("LeftScrn",  "Activity3");
   theActivity1Intent.putExtra("RightScrn", "Activity2");
   theActivity1Intent.putExtra("Tag", A1);


   theActivity2Intent = new Intent(this, Activity2.class);
   theActivity2Intent.putExtra("LeftScrn",  "Activity1");
   theActivity2Intent.putExtra("RightScrn", "Activity3");
   theActivity2Intent.putExtra("Tag", A2);


   theActivity3Intent = new Intent(this, Activity3.class);
   theActivity3Intent.putExtra("LeftScrn",  "Activity2");
   theActivity3Intent.putExtra("RightScrn", "Activity1");
   theActivity3Intent.putExtra("Tag", A3);



   theIntentList = new ArrayList<Intent>();
   theIntentList.add(theActivity1Intent);
   theIntentList.add(theActivity2Intent);
   theIntentList.add(theActivity3Intent);
   theMaxIndex = theIntentList.size()-1;

}// end onCreate
See, we don’t to instantiate or save Activities, we need to define the Intents and then let Android do the work.  Additionally notice that we are using the putExtra Feature to assign name value pairs to the Intent that can be used, or ignored, by the Activity.  Next review the updated onClick call to start the Activity
public void onClick(View v)
{

   // Launching the activity to get a result when it finished. When this
   // activity exits, onActivityResult() method will be called with the
   // given requestCode. Using a negative requestCode is the same as calling
   // startActivity(Intent) (the activity is not launched as a sub-activity).
   // parameters
   // intent - the intent to start
   // request code - If >= 0, this code will be returned in onActivityResult()
   //                when the activity exits.

   startActivityForResult( theActivity1Intent,
                           theIntentList.get(theCurrIndex)
.getExtras()
                                                          .getInt("Tag"));
}

Now we can get some data back and decide how to proceed from there.  This code is a little more lengthy.
/**
   * onActivityResult
   * Called when an activity you launched exits, giving the requestCode you
   * started it with, the resultCode it returned, and any additional data.
   * The resultCode == RESULT_CANCELED if the activity explicitly returned
   * that, didn't return any result, or crashed during its operation.
   * You will receive this call immediately before onResume() when your
   * activity is re-starting.
   * I am using this function to determine if I need to nav left or right
   * Parameters
   * @param requestCode - The integer request code originally supplied to
   *                      startActivityForResult(), allowing you to identify
   *                      who this result came from.
   * @param resultCode  - Integer result code returned by the child activity
   *                      through its setResult().
   * @param data        - An Intent, can return result data to the caller
   *                      (various data can be attached to Intent "extras").
   */

  protected void onActivityResult(int requestCode,

                                  int resultCode,
                                  Intent data)
  {
     // Regardless of which screen exited and is telling to go left or right
     // we need to determine the left and right indexes

     // Left index - if the current index is not zero then left is minus one
     //              otherwise if zero the actual left is the end of the list

     int leftIndex  = (theCurrIndex != 0) ? theCurrIndex-1 : theMaxIndex;
     // Right index - if the current index is the end of the list then right
     //               the the beginning of the list or zero, otherwise right

     //               is plus one
     int rightIndex = (theCurrIndex == theMaxIndex) ? 0 : theCurrIndex+1;

     // Get the extra from the Intent that tells us left or right.
     // NOTE - you need to check for null, if the user presses the back btn
     //        there will not be an Intent attached and data will be null

     String dir = "";
     if (null!= data)
     {
        dir = data.getStringExtra("Go");
     }
     // the Activity set this value if it was returning normally
     if (RESULT_OK == resultCode)
     {
        if ( 0 == dir.compareTo("left"))
        {
           theCurrIndex = leftIndex;
        }
        else if (0 == dir.compareTo("right"))
        {
           theCurrIndex = rightIndex;
        }
        else
        {
           // intentionally do nothing        }
        // Get the Intent
        Intent nextIntent = theIntentList.get(theCurrIndex);
        // Get the tag
        int    tagValue   = theIntentList.get(theCurrIndex)

                                         .getExtras().getInt("Tag");
        // Start the new Activity
        startActivityForResult( nextIntent, tagValue);


     }// end if (RESULT_OK == resultCode)
  
 
  }// end onActivityResult

Not shown is how in the actual Activity class before it returns to the main Activity is how it does its own putExtra on the returning Intent.  Additionally the Activity calls its onFinish().  This lets Android know that we are done with this Activity and lets it do any needed management.
I’m sure there are slicker/better ways to handle this.  Its what I’ve got for know.  Feel free to let me know if you know of a smarter way!

No comments:

Post a Comment