SyntaxHighlighter

Monday, August 30, 2010

Telnet and your Android Emulator

Did you know you can telnet into an Android emulator/AVD?  Assuming that you have telnet installed and have created an AVD, its very easy. 
  1. On your Android AVD’s title bar you should see the name of your emulator with some numbers pre-pended to it.  That is the console port number of your AVD.
  2. Open a command window and type “telnet localhost <the number>” NOTE – don’t type the brackets, just the number.
  3. Your command window should be updated to show the connection.  Type help to get a valid command list.

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!

Blogging isn’t as easy as it looks

image This is not really an Android focused post so much as it is a post on posting.  How’s  that for an opening sentence?  As someone used to writing in Word and PowerPoint it was surprisingly hard to get my first posts formatted like I wanted.  Just too used to be able to copy and paste images and copy in code snippets.  I was under the impression that I could continue that normal way of business.  This was reinforced by the fact that my first blog experience (with SharePoint) I was able to pretty much copy from Word into the SharePoint blog interface.  Even then the whole process felt like it was much harder than it should be.  I had an even ruder awakening when I tried to copy over a blog from SharePoint hosted to Blogger.  Having code snippets (XML for that matter) does not make the Blogger interface happy.  After quite some time hunting around I found my tool of choice – for now – Windows Live Writer.  So far it seems to be doing a good job of keeping me in my comfort zone and streamlining the publishing.  If you have something better let me know!  I’m not shy about upgrading if it makes things easier.
One thing that did throw me off about blogger was the width of the actual blog interface.  The default is surprisingly narrow to me and it was more difficult than expected to update.  But find it I did.  I’m posting it here since I’m sure I’ll forget how I did it later. 
(1) Go to your design tab in your Blogger dashboard
(2) Select Edit HTML and then search for something like this:
<b:variable default='930px' name='content.width' type='length' value='1200px'/>
(3) Change the value to what you want and save.  DISCLAIMER – you may want to backup your original template first.

Friday, August 27, 2010

Break out your Layout

Recently I faced the issue of needed to reuse a particular layout on multiple screens.  If you are like me you have to copy and paste code.  Anytime I find I need something more than once I look for a way to get some reuse.  Luckily Android has provided a few easy ways to do this when creating your screens.  I'm actually using 2 different ways on my current program.  Take a look at <ViewStub> and <include>, both work very well.
Let’s look at how we can use these in a layout file.
<LinearLayout>
    <!-- The include will load in the layout files -->
    <include android:id="@+id/theStatusBar" layout="@layout/statusbar" />
    <!-- The ViewStub will wait for you to tell them to inflate -->
    <ViewStub android:id="@+id/theView1Stub"
              android:layout_width ="fill_parent"
              android:layout_height="wrap_content"
              android:layout="@layout/view1" />
    <ViewStub android:id="@+id/theView2Stub"
              android:layout_width ="fill_parent"
              android:layout_height="wrap_content"
              android:layout="@layout/view2" >
</LinearLayout>
So in the snippet above, we have two includes and two ViewStubs. The significant difference being the <include> will automatically load in the layout specified and inflate/display it in your Activity’s layout. So when the Activity’s onCreate is called and the setContentView is specified Android will do the magic for you.
Why use <ViewStub> too? Perhaps you need to customize your screen depending on some flag or parameter. Since a ViewStub is not inflated until you tell it, it can be useful. In this example I have a base class that extends from Activity that has the above in its layout file. I also have two other Activity classes that inherit from it. Since the status bar is needed by both screens, the base class can handle loading and controlling that for its children. Each child in its onCreate can then inflate itself once it is started. So in each child class is a line of code to inflate their applicable Viewstub
// inflate ourselves into the layout ViewStub
View view = ((ViewStub) findViewById(R.id.theView1Stub)).inflate();
Check out these online resources here for more info:
Layout Tricks: Creating Reusable UI Components
Layout Tricks: Creating Efficient Layouts
Layout Tricks: Using ViewStubs
Layout Tricks: Merging Layouts