Android Activity State Changes - An Example Application

From Techotopia
Revision as of 19:16, 17 May 2012 by Neil (Talk | contribs) (New page: <table border="0" cellspacing="0" width="100%"> <tr> <td width="20%">Previous<td align="center">[[Kindle Fire Development Essentials|Table of Co...)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
PreviousTable of ContentsNext
Handling Android Activity State ChangesSaving and Restoring the User Interface State of an Android Activity


<google>BUY_KINDLE_FIRE</google>


The previous chapters have discussed in some detail the different states and lifecycles of the activities that comprise an Android application. In this chapter we will put the theory of handling activity state changes into practice through the creation of an example application. The purpose of this example application is to provide a real world demonstration of an activity as it passes through a variety of different states within the Android runtime, and also to highlight the implications of failing to adequately save and restore state.

In the next chapter, entitled Saving and Restoring the User Interface State of an Android Activity, the example project constructed in this chapter will be extended to demonstrate the saving and restoration of dynamic user interface state.


Contents


Creating the State Change Example Project

The first step in this exercise is to create the new project. To this end, launch Eclipse and select the File -> New -> Project… menu option. Within the resulting new project dialog, select the Android Project wizard before clicking Next to continue. In the following screen, select the Create new project in workspace option and name the project StateChange. Click Next and select Android 2.3.3 as the build target before proceeding once again to the next screen. On the Application Info screen specify the package name using your reverse domain name and the application name as outlined in Creating an Example Kindle Fire Android Application (for example com.mycompany.StateChange). Verify that the Create Activity option is selected and that Minimum SDK is set to 10 before clicking on the Finish button.

Upon completion of the project creation process, the StateChange project should be listed in the Package Explorer panel located along the left hand edge of the Eclipse main window.

Creating a Kindle Fire Device Configuration

When the new project was created, Eclipse was instructed to create a new activity. As outlined in previous chapters, an activity typically corresponds to one user interface screen. Eclipse has, therefore, also created a user interface for our activity and placed the layout resources for it in a file named main.xml. At this point this is simply a placeholder consisting of a LinearLayout and a TextView object. The next step is to modify this to meet the specific requirements of our example application. Before doing so, however, we need to take some time to talk about device configurations.

Begin by navigating to the main.xml file within the Project Explorer by unfolding the StateChange -> res -> layout subfolders. Once the main.xml file is located, double click on it to load it into the user interface design tool as illustrated in Figure 10 1:


The example project loaded into Eclipse

Figure 10-1


By default, Eclipse assumes that a user interface is being designed for the screen of a 3.7in Nexus One smart phone. Clearly this is considerably smaller than the Kindle Fire display. Whilst this isn’t necessarily a problem if you plan to use relative positioning for all the components of the user interface (something that is actually recommended if the application is to be deployed on a variety of Android devices with differing screen sizes) it is important to keep this issue in mind when working with absolute positioning of components in a user interface. For the purposes of this example we will work through the steps to create a new device configuration specifically for the Kindle Fire.

Begin by selecting the drop down menu item which currently displays 3.7in WVGA (Nexus One) as outlined in Figure 10-2:


Changing the device configuration in the Eclipse Android SDK UI builder

Figure 10-2


Select the Custom… option from the menu and, in the resulting Device Configurations screen, select the Custom entry from the bottom of the list before clicking on the New… button.

Within the new configuration dialog, enter KindleFire as both the Device and Configuration name. From the Available Qualifiers list, select the Screen Width option and click on the right pointing arrow button. In the resulting Screen Width field, enter the value of 600. Repeat this step to set the Screen Height value to 1024:


Creating a new Android SDK device configuration for the Kindle Fire

Figure 10-3


Remaining within the device configuration dialog, add the following device qualifiers:

  • Dimension – 1024 x 600
  • Touch Screen – Finger
  • Keyboard – Soft
  • Ratio – Long
  • Size – Large

Once the device configuration is completed, click on the OK button in both configuration dialogs to return to the interface builder panel. Using the configuration drop down menu, select the new KindleFire device configuration and note that the visual representation of the screen within the interface builder adjusts to reflect the size of the Kindle Fire display. If necessary, use the resize controls (the row of button containing magnifying glass icons on the right hand side of the user interface builder toolbar) to adjust the zoom level of the screen view.


Designing the User Interface

With the device configuration created and selected, it is now time to design the user interface for the example application. As with the example created in the chapter entitled Creating an Example Kindle Fire Android Application, we will replace the LinearLayout provided for us by Eclipse with a RelativeLayout. This time, however, rather than delete the existing LinearLayout and create a new RelativeLayout object, we will simply use the interface builder tool to change the type of the current layout. To achieve this, locate the Outline panel in the main Eclipse window and Ctrl-click or right click on the LinearLayout entry to display the menu shown in Figure 10-4.


[[Image:|The Eclipse Outline context menu with option to change layout type]]

Figure 10-4


From within the menu, select the Change Layout… menu option and in the resulting Change Layout dialog change the New Layout Type menu to RelativeLayout and click on OK. Note that this menu is also available by clicking in the same manner on the layout in the visual representation of the screen (in this case the black background).

Instead of the TextView currently present in the user interface design, the activity actually requires an EditText object. Right or Ctrl-click on the TextView object, either in the Outline panel or in the view itself, this time selecting Change Widget Type from the resulting menu. In the Change Widget Type dialog select Edit Text from the New Widget Type menu and click on OK to commit the change.

The final step is to move the newly converted EditText object to the center of the screen by dragging and dropping it into position in the view. Once completed, the user interface design should resemble that of Figure 10-5:


The user interface of an example Kindle Fire Android activity designed to show state changes

Figure 10-5


Overriding the Activity Lifecycle Methods

At this point the project contains a single activity named StateChangeActivity which is, as with all activities, derived from the Android Activity class. The source code for this activity is contained within the StateChangeActivity.java file. Navigate to this file in the Project Explorer panel (StateChange -> src -> com.yourcompany.StateChange -> StateChangeActivity.java) and double click on it to load the file into the editor pane. Once loaded the code should read as follows:

package com.ebookfrenzy.StateChange;

import android.app.Activity;
import android.os.Bundle;

public class StateChangeActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

So far the only lifecycle method overridden by the activity is the onCreate() method which has been implemented so as to call the super class instance of the method before setting up the user interface for the activity. We will now modify this method so that it outputs a diagnostic message in the Eclipse Log panel each time it executes. For this we will use the Log class, which requires that we import android.util.Log and declare a tag that will enable us to filter these messages in the log output:

package com.ebookfrenzy.StateChange;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class StateChangeActivity extends Activity {
	
    private static final String TAG = "com.ebookfrenzy.StateChange";
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.i(TAG, "onCreate");
    }
}

The next task is to override some more methods, with each one containing a corresponding log call:

	protected void onStart() {
		super.onStart();
		Log.i(TAG, "onStart");
	}
	
	protected void onResume() {
		super.onResume();
		Log.i(TAG, "onResume");
	}
	
	protected void onPause() {
		super.onPause();
		Log.i(TAG, "onPause");
	}
	
	protected void onStop() {
		super.onStop();
		Log.i(TAG, "onStop");
	}
	
	protected void onRestart() {
		super.onRestart();
		Log.i(TAG, "onRestart");
	}

	protected void onDestroy() {
		super.onDestroy();
		Log.i(TAG, "onDestroy");
	}

	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		Log.i(TAG, "onSaveInstanceState");
	}
	
	protected void onRestoreInstanceState(Bundle savedState) {		
		Log.i(TAG, "onRestoreInstanceState");
	}

Enabling and Filtering the LogCat Panel

The purpose of the code added to the overridden methods in StateChangeActivity.java is to output logging information to the LogCat panel within the main Eclipse window. By default this panel is not displayed so it will be necessary to configure Eclipse to display it before running the application.

To enable LogCat, select the Window -> Show View -> Other… menu option and in the Show View dialog select LogCat and click on OK. An additional tab labeled LogCat should now be present next to the Console tab in the bottom panel of the Eclipse window as shown in Figure 10-6:


The Eclipse LogCat panel with unfiltered output

Figure 10-6


With no filters defined, the log will list every logged event that takes place within a running application thereby making it all but impossible to find the log messages for our overridden methods. Before running the application, therefore, it is necessary to create a filter which, when selected, will ensure that only log messages that contain the tag declared in our activity are displayed.

With the LogCat panel displayed, click on the green ‘+’ located to the right of the Save Filters title to display the filter settings dialog (Figure 10-7). Name the filter Lifecycle and in the by Log Tag field, enter the Tag value declared in StateChangeActivity.java (in the above code example this was com.ebookfrenzy.StateChange but you may have changed this to reflect your company’s URL).


Creating an Eclipse LogCat filter

Figure 10-7


When the changes are complete, click on the OK button to create the filter and dismiss the dialog.

Running the Application

For optimal results, the application should be run on a physical Kindle Fire device, details of which can be found in the chapter entitled Testing Android Applications on a Physical Kindle Fire Device. With the Kindle Fire device configured and connected to the development computer, Ctrl-click or right click on the StateChange entry in the Project Explorer panel and select Run As -> Android Application. Select the physical Kindle Fire device from the Android Device Chooser dialog if it appears (assuming that you have not already configured it to be the default target) and then, with the Kindle Fire device still connected to the computer, take the usual steps to wake up and access the device. At this point the application should be running in the foreground.

A review of the LogCat panel should indicate the methods which have so far been triggered (taking care to ensure that the Lifecycle filter created in the preceding section is selected to filter out log events that are not currently of interest to us):


Filtered LogCat output showing calls to Android Activity lifecycle methods

Figure 10-8

Experimenting with the Activity

With the diagnostics working it is now time to exercise the application with a view to gaining an understanding of the activity lifecycle state changes. To begin with, consider the initial sequence of log events in the LogCat panel:

onCreate
onStart
onResume
onSaveInstanceState
onPause
onResume

Clearly the initial state changes are exactly as outlined in Figure 9 1. Note, however, that a call was not made to onRestoreInstanceState() since the Android runtime detected that there was no state to restore in this situation. The subsequent calls to onSaveInstanceState(), onPause() and onResume() are slightly less obvious at first glance. Consider, however, the sequence of steps performed in the previous section. The application was actually launched while the device display was turned off. The runtime, therefore, detected that the activity was not visible to the user and, as a result, paused the activity as soon as it was appropriate to do so. When the device was woken up and the activity became visible the onResume() method was called to let the activity know.

With the application still running on the device, touch the Settings icon in the top status bar of the display (the gear cog icon). The settings activity will appear over the top of the StateChangeActivity user interface, partially obscuring it and taking away focus. Refer to the LogCat panel and note that the Android runtime has, once again, paused the activity. Tap once again on our activity to dismiss the settings panel and the log will indicate a call to onResume().

Tap on the Home icon in the bottom status bar on the Kindle Fire display and note a sequence of method calls reported in the log file as follows:

onSaveInstanceState
onPause
onStop

Clearly the runtime has noticed that the activity is no longer in the foreground, is not visible to the user and has stopped the activity, but not without providing an opportunity for the activity to save the dynamic state. Depending on whether the runtime ultimately destroyed the activity or simply restarted it, the activity will either be notified it has been restarted via a call to onRestart() or will go through the creation sequence again when the user returns to the activity.

As outlined in Understanding Android Application and Activity Lifecycles, the destruction and recreation of an activity can be triggered by making a configuration change to the device, such as rotating from portrait to landscape. To see this in action, simply rotate the Kindle Fire device while the StateChange application is in the foreground. The resulting sequence of method calls in the log should read as follows:

onSaveInstanceState
onPause
onStop
onDestroy
onCreate
onStart
onRestoreInstanceState
onResume

Clearly, the runtime system has given the activity an opportunity to save state before destroying and restarting the activity.

Saving Dynamic State

So far in this example no steps have been taken to save the dynamic state of the activity. Although appropriate methods have been overridden, no code other than a log output has been implemented. The importance of implementing this functionality can be demonstrated using the example application. With the device in portrait orientation and the activity in the foreground, touch inside the EditText field so that the virtual keyboard comes into view and, using the keyboard, delete the current text and enter some new text into the box. Make a mental note of the change made to the text before rotating the device into landscape orientation. As should be evident, the changes made to the text have been lost. This is, quite simply, because no steps have been taken to ensure that state is saved and restored in the event that the activity is destroyed and recreated. This will be the main focus of the next chapter, entitled Saving and Restoring the User Interface State of an Android Activity.

Summary

The old adage that a picture is worth a thousand words holds just as true for examples when learning a new programming paradigm. In this chapter we have created an example Android application for the Kindle Fire for the purpose of demonstrating the different lifecycle states through which an activity is likely to pass. The example was then used to highlight the importance of saving and restoring dynamic state in order to provide the user with a consistent and seamless user interface experience.

In the course of developing the project in this chapter we also looked at a mechanism for generating diagnostic logging information from within an activity, and also explored the steps involved in creating a Kindle Fire specific device configuration for the Android SDK’s user interface builder.

In the next chapter we will extend the StateChange example project to demonstrate how to save and restore an activity’s dynamic state.


<google>BUY_KINDLE_FIRE</google>



PreviousTable of ContentsNext
Handling Android Activity State ChangesSaving and Restoring the User Interface State of an Android Activity