Friday, May 25, 2012

How do I save an Android application"s state?


I've been playing around with the Android SDK, and I am a little unclear on saving an applications state. So given this minor re-tooling of the 'Hello, Android' example:




package com.android.hello;

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

public class HelloAndroid extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mTextView = new TextView(this);

if (savedInstanceState == null) {
mTextView.setText("Welcome to HelloAndroid!");
} else {
mTextView.setText("Welcome back.");
}

setContentView(mTextView);
}

private TextView mTextView = null;
}



I thought that might be all one needed to do for the simplest case, but it always gives me the first message, no matter how I navigate away from the app. I'm sure it's probably something simple like overriding onPause or something like that, but I've been poking away in the docs for 30 minutes or so and haven't found anything obvious, so would appreciate any help.



Cue me looking a fool in three, two, one...



Thanks.


Source: Tips4all

6 comments:

  1. You need to override onSaveInstanceState(Bundle savedInstanceState) and write the application state values you want to change to the Bundle parameter like this:

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save UI state changes to the savedInstanceState.
    // This bundle will be passed to onCreate if the process is
    // killed and restarted.
    savedInstanceState.putBoolean("MyBoolean", true);
    savedInstanceState.putDouble("myDouble", 1.9);
    savedInstanceState.putInt("MyInt", 1);
    savedInstanceState.putString("MyString", "Welcome back to Android");
    // etc.
    super.onSaveInstanceState(savedInstanceState);
    }


    The Bundle is essentially a way of storing a NVP ("Name-Value Pair") map, and it will get passed in to onCreate and also onRestoreInstanceState where you'd extract the values like this:

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    // Restore UI state from the savedInstanceState.
    // This bundle has also been passed to onCreate.
    boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
    double myDouble = savedInstanceState.getDouble("myDouble");
    int myInt = savedInstanceState.getInt("MyInt");
    String myString = savedInstanceState.getString("MyString");
    }


    You'd usually use this technique to store instance values for your application (selections, unsaved text, etc.).

    ReplyDelete
  2. The savedInstanceState is only for saving state associated with a current instance of an Activity, for example current navigation or selection info, so that if Android destroys and recreates an Activity, it can come back as it was before. See the documentation for onCreate and onSaveInstanceState

    For more long lived state, consider using a SQLite database, a file, or preferences. See Saving Persistent State.

    ReplyDelete
  3. Note that it is NOT safe to use onSaveInstanceState and onRestoreInstanceState, according to the documentation on Activity states in http://developer.android.com/reference/android/app/Activity.html.

    The document states (in the 'Activity Lifecycle' section):


    Note that it is important to save
    persistent data in onPause() instead
    of onSaveInstanceState(Bundle)
    because the later is not part of the
    lifecycle callbacks, so will not be
    called in every situation as described
    in its documentation.


    In other words, put your save/restore code in onPause() and onResume() instead!

    ReplyDelete
  4. My colleague wrote an article explaining Application State on Android devices including explanations on Activity Lifecycle and State Information, How to Store State Information, and saving to State Bundle and SharedPreferences.
    http://www.eigo.co.uk/Managing-State-in-an-Android-Activity.aspx

    ReplyDelete
  5. onSaveInstanceState is called when the system needs memory and kills an application. It is not called when the user just closes the application. So I think application state should also be saved in onPause. It should be saved to some persistent storage like Preferences or Sqlite.

    ReplyDelete
  6. Both methods are useful and valid and both are best suited for different scenarios:


    The user terminates the application and re-opens it at a later date, but the application needs to reload data from the last session – this requires a persistent storage approach such as using SQLite.
    The user switches application and then comes back to the original and wants to pick up where they left off - save and restore bundle data (such as application state data) in onSaveInstanceState() and onRestoreInstanceState() is usually adequate.


    If you save the state data in a persistent manner, it can be reloaded in an onResume() or onCreate() (or actually on any lifecycle call). This may or may not be desired behaviour. If you store it in a bundle in an InstanceState, then it is transient and is only suitable for storing data for use in the same user ‘session’ (I use the term session loosely) but not between ‘sessions’.

    It is not that one approach is better than the other, like everything, it is just important to understand what behaviour you require and to select the most appropriate approach.

    ReplyDelete