tags:

views:

24227

answers:

6

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.

+25  A: 

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.

Dave L.
+1 `onSaveInstanceState` is only for _transient_ state. You should save permanent changes in the `onPause` method.
Dave Webb
+46  A: 

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 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.).

Reto Meier
Ahh. That's what I was looking for; thank you.
Bernard
In onRestoreInstanceState, I think you mean for the first line to be super.onRestoreInstanceState rather than super.onSaveInstanceState
Dave L.
Any chance this works on the phone, but not in the emulator? I cannot seem to get a non-null savedInstanceState.
Adam Jack
+1  A: 

onSaveInstanceState is called when system needs memory and kills my application. It is not called when 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 on Sqlite.

Fedor
A: 

Really onSaveInstance state callen when the Activity goes to background

Quote from the docs: "the method onSaveInstanceState(Bundle) is called before placing the activity in such a background state"

A: 

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!

Steve Moseley
Just to nitpick: it's not unsafe either. This just depends on what you want to preserve and for how long, which @Bernard isn't entirely clear on in his original question. InstanceState is perfect for preserving the current UI state (data entered into controls, current positions in lists and so forth), whereas Pause/Resume is the only possibility for long term persistent storage.
Pontus Gagge
This should be downvoted like hell. It's not safe to use on(Save|Restore)InstanceState like lifecycle methods (i.e. do anything else in them than save / restore the state). They're perfectly good for saving / restoring state. Also, how do you want to save / restore state in onPause and onResume? You don't get Bundles in those methods that you can use, so you'd have to employ some other state-saving, in databases, files, etc. which is stupid.
Felix
+3  A: 

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

Eigo