Walkthrough - Saving the Activity state

We have covered the theory behind saving state in the Activity Lifecycle guide; now, let's walk through an example.

Activity State Walkthrough

Let's open the ActivityLifecycle_Start project (in the ActivityLifecycle sample), build it, and run it. This is a very simple project that has two activities to demonstrate the activity lifecycle and how the various lifecycle methods are called. When you start the application, the screen of MainActivity is displayed:

Activity A screen

Viewing State Transitions

Each method in this sample writes to the IDE application output window to indicate activity state. (To open the output window in Visual Studio, type CTRL-ALT-O; to open the output window in Visual Studio for Mac, click View > Pads > Application Output.)

When the app first starts, the output window displays the state changes of Activity A:

[ActivityLifecycle.MainActivity] Activity A - OnCreate
[ActivityLifecycle.MainActivity] Activity A - OnStart
[ActivityLifecycle.MainActivity] Activity A - OnResume

When we click the Start Activity B button, we see Activity A pause and stop while Activity B goes through its state changes:

[ActivityLifecycle.MainActivity] Activity A - OnPause
[ActivityLifecycle.SecondActivity] Activity B - OnCreate
[ActivityLifecycle.SecondActivity] Activity B - OnStart
[ActivityLifecycle.SecondActivity] Activity B - OnResume
[ActivityLifecycle.MainActivity] Activity A - OnStop

As a result, Activity B is started and displayed in place of Activity A:

Activity B screen

When we click the Back button, Activity B is destroyed and Activity A is resumed:

[ActivityLifecycle.SecondActivity] Activity B - OnPause
[ActivityLifecycle.MainActivity] Activity A - OnRestart
[ActivityLifecycle.MainActivity] Activity A - OnStart
[ActivityLifecycle.MainActivity] Activity A - OnResume
[ActivityLifecycle.SecondActivity] Activity B - OnStop
[ActivityLifecycle.SecondActivity] Activity B - OnDestroy

Adding a Click Counter

Next, we're going to change the application so that we have a button that counts and displays the number of times it is clicked. First, let's add a _counter instance variable to MainActivity:

int _counter = 0;

Next, let's edit the Resource/layout/Main.axml layout file and add a new clickButton that displays the number of times the user has clicked the button. The resulting Main.axml should resemble the following:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:id="@+id/myButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/mybutton_text" />
    <Button
        android:id="@+id/clickButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/counterbutton_text" />
</LinearLayout>

Let's add the following code to the end of the OnCreate method in MainActivity – this code handles click events from the clickButton:

var clickbutton = FindViewById<Button> (Resource.Id.clickButton);
clickbutton.Text = Resources.GetString (
    Resource.String.counterbutton_text, _counter);
clickbutton.Click += (object sender, System.EventArgs e) =>
{
    _counter++;
    clickbutton.Text = Resources.GetString (
        Resource.String.counterbutton_text, _counter);
} ;

When we build and run the app again, a new button appears that increments and displays the value of _counter on each click:

Add touch count

But when we rotate the device to landscape mode, this count is lost:

Rotating to landscape sets the count back to zero

Examining the application output, we see that Activity A was paused, stopped, destroyed, recreated, restarted, then resumed during the rotation from portrait to landscape mode:

[ActivityLifecycle.MainActivity] Activity A - OnPause
[ActivityLifecycle.MainActivity] Activity A - OnStop
[ActivityLifecycle.MainActivity] Activity A - On Destroy

[ActivityLifecycle.MainActivity] Activity A - OnCreate
[ActivityLifecycle.MainActivity] Activity A - OnStart
[ActivityLifecycle.MainActivity] Activity A - OnResume

Because Activity A is destroyed and recreated again when the device is rotated, its instance state is lost. Next, we will add code to save and restore the instance state.

Adding Code to Preserve Instance State

Let's add a method to MainActivity to save the instance state. Before Activity A is destroyed, Android automatically calls OnSaveInstanceState and passes in a Bundle that we can use to store our instance state. Let's use it to save our click count as an integer value:

protected override void OnSaveInstanceState (Bundle outState)
{
    outState.PutInt ("click_count", _counter);
    Log.Debug(GetType().FullName, "Activity A - Saving instance state");

    // always call the base implementation!
    base.OnSaveInstanceState (outState);    
}

When Activity A is recreated and resumed, Android passes this Bundle back into our OnCreate method. Let's add code to OnCreate to restore the _counter value from the passed-in Bundle. Add the following code just before the line where clickbutton is defined:

if (bundle != null)
{
    _counter = bundle.GetInt ("click_count", 0);
    Log.Debug(GetType().FullName, "Activity A - Recovered instance state");
}

Build and run the app again, then click the second button a few times. When we rotate the device to landscape mode, the count is preserved!

Rotating the screen shows count of four preserved

Let's take a look at the output window to see what happened:

[ActivityLifecycle.MainActivity] Activity A - OnPause
[ActivityLifecycle.MainActivity] Activity A - Saving instance state
[ActivityLifecycle.MainActivity] Activity A - OnStop
[ActivityLifecycle.MainActivity] Activity A - On Destroy

[ActivityLifecycle.MainActivity] Activity A - OnCreate
[ActivityLifecycle.MainActivity] Activity A - Recovered instance state
[ActivityLifecycle.MainActivity] Activity A - OnStart
[ActivityLifecycle.MainActivity] Activity A - OnResume

Before the OnStop method was called, our new OnSaveInstanceState method was called to save the _counter value in a Bundle. Android passed this Bundle back to us when it called our OnCreate method, and we were able to used it to restore the _counter value to where we left off.

Summary

In this walkthough, we have used our knowledge of the Activity Lifecycle to preserve state data.