Saving and Restoring the User Interface State of an Android Activity

From Techotopia
Revision as of 14:24, 21 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 Esse...)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
PreviousTable of ContentsNext
Android Activity State Changes – An Example Application


<google>BUY_KINDLE_FIRE</google>


If the previous few chapters have achieved their objective, it should now be a little clearer as to why it is important to save and restore the state of a user interface at particular points in the lifetime of an activity. As was demonstrated in the previous chapter, failure to save and restore state can result in the user losing information entered into a screen, even when performing an action as simple as rotating the device between portrait and landscape orientations.

In this chapter we will extend the example application created in Android Activity State Changes – An Example Application so that the EditText field no longer loses changes made by the user when the activity is destroyed and recreated by the runtime system.

A key component of saving and restoring dynamic state involves the use of the Android SDK Bundle class, a topic that will also be covered in this chapter.


Contents


Saving Dynamic State

An activity, as we have already learned, is given the opportunity to save dynamic state information via a call from the runtime system to the activity’s implementation of the onSaveInstanceState() method. Passed through as an argument to the method is a reference to a Bundle object into which the method will need to store any dynamic data that needs to be saved. The Bundle object is then stored by the runtime system on behalf of the activity and subsequently passed through as an argument to the activity’s onCreate() and onRestoreInstanceState() methods if and when they are called. The data can then be retrieved from the Bundle object within these methods and used to restore the state of the activity.

The Bundle Class

The Bundle class provides a container mechanism for storing data using a key-value pair mechanism. The keys take the form of string values whilst the values associated with those keys can be in the form of a primitive value or any object that implements the Android Parcelable interface. A wide range of classes already implement the Parcelable interface. Custom classes may be made “parcelable” by implementing the range of methods defined in the Parcelable interface (details of which can be found in the Android documentation at http://developer.android.com/reference/android/os/Parcelable.html).

The Bundle class also contains a set of methods that can be used to get and set key-value pairs for a variety of data types including both primitive types (including boolean, char, double and float values) and objects (such as Strings and CharSequences).

For the purposes of this example, we need to make sure that the text entered into the EditText field by the user is saved into the Bundle object and subsequently restored. This will be achieved by using the putCharSequence() and getCharSequence() methods of the Bundle class respectively.


Saving the State

The first step in extending the StateChange application is to make sure that the text entered by the user is extracted from the EditText component within the onSaveInstanceState() method of the StateChangeActivity activity, and then saved as a key-value pair into the Bundle object.

In order to extract the text from the EditText object we first need to identify that object in the user interface. Clearly this involves bridging the gap between the Java code for the activity (contained in the StateChangeActivity.java source code file) and the XML representation of the user interface (contained within the main.xml resource file). In order to extract the text entered into the EditText component we need to gain access to that user interface object.

Each component within a user interface has associated with it a unique identifier. By default, the interface builder tool constructs the ID for a newly added component from the object type followed by a sequential number (though this can, and should, be changed to something more meaningful by the developer). As can be seen by checking the Outline panel within the main Eclipse window, in the case of the EditText component, the object has been assigned ID EditText1.

As outlined in the chapter entitled The Anatomy of an Android Application, all of the resources that make up an application are compiled into a class named R. Amongst those resources are those that define layouts, including the layout for our current activity. Within the R class is a subclass named layout which contains the layout resources, and within that subclass is our main layout. With this knowledge, we can make a call to the findViewById() method of our activity object to get a reference to the EditText1 object as follows:

final EditText textBox = (EditText) findViewById(R.id.EditText1);

Having obtained a reference to the EditText object and assigned it to textBox, we can now obtain the text that it contains by calling the object’s getText() method which, in turn, returns the current text in the form of a CharSequence object:

CharSequence userText = textBox.getText();

Finally, we can save the text using the Bundle object’s putCharSequence() method, passing through the key (this can be any string value but in this instance we will declare it as “savedText”) and the userText object as arguments:

outState.putCharSequence("savedText", userText);

Bringing this all together gives us a modified onSaveInstanceState() method in the StateChangeActivity.java file which reads as follows (noting also the additional import directive for android.widget.EditText):

package com.ebookfrenzy.StateChange;

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

public class StateChangeActivity extends Activity {
.
.
.
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		Log.i(TAG, "onSaveInstanceState");
		
		final EditText textBox = 
                   (EditText) findViewById(R.id.EditText1);
		CharSequence userText = textBox.getText();
		outState.putCharSequence("savedText", userText);
	}
.
.
.

Now that steps have been taken to save the state, the next phase is to ensure that it is restored when needed.

Restoring the State

The saved dynamic state can be restored in those methods which are passed the Bundle object as an argument. This leaves the developer with the choice of using either onCreate() or onRestoreInstanceState(). The method to use will depend on the nature of the activity. In instances where state is best restored after the activity’s initialization tasks have been performed, the onRestoreInstanceState() method is generally more suitable. For the purposes of this example we will add code to the onRestoreInstanceState() method to extract the saved state from the Bundle using the “savedText” key. We can then assign the text to the EditText1 component using the object’s setText() method:

protected void onRestoreInstanceState(Bundle savedState) {		
		Log.i(TAG, "onRestoreInstanceState");
		
		final EditText textBox = 
               (EditText) findViewById(R.id.EditText1);
		
		CharSequence userText = 
               savedState.getCharSequence("savedText");
		
		textBox.setText(userText);
	}

Testing the Application

All that remains is to once again test the StateChange application. Verify that your Kindle Fire device is connected to the USB port of your development system, Ctrl-click or right-click on the StateChange item in the Package Explorer window and select the Run as -> Android Application. Make any necessary selections to ensure the Kindle Fire is the target device and launch the application.

Once running and in the foreground, touch the EditText component and change the text using the virtual keyboard before rotating the device to another orientation. Whereas the text changes were lost in the previous chapter, the new text is retained within the EditText component thanks to the code we have added to the activity in this chapter.

Summary

The saving and restoration of dynamic state in an Android application is simply a matter of implementing the appropriate code in the right lifecycle methods. This typically consists of extracting values and settings from the components in the user interface within the onSaveInstanceState() method (using the activity’s findViewbyId() method if the user interface is stored in a resource file) and saving the data as key-value pairs within the Bundle object passed through to the activity by the runtime system. State can be restored in either the onCreate() or the onRestoreInstanceState() method of the activity by extracting values from the Bundle object and updating the user interface accordingly.

In this chapter we have used these techniques to update the StateChange project so that the user interface retains changes through the destruction and subsequent recreation of an activity.


<google>BUY_KINDLE_FIRE</google>



PreviousTable of ContentsNext
Android Activity State Changes – An Example Application