I've been working on the Android SDK platform, and it is a little unclear how to save an application's 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 {
private TextView mTextView = null;
/** 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);
}
}
I thought it would be enough for the simplest case, but it always responds with the first message, no matter how I navigate away from the app.
I'm sure the solution is as simple as overriding onPause
or something like that, but I've been poking away in the documentation for 30 minutes or so and haven't found anything obvious.
Both methods are useful and valid and both are best suited for different scenarios:
onSaveInstanceState()
andonRestoreInstanceState()
is usually adequate.If you save the state data in a persistent manner, it can be reloaded in an
onResume()
oronCreate()
(or actually on any lifecycle call). This may or may not be desired behaviour. If you store it in a bundle in anInstanceState
, 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.
Now Android provides ViewModels for saving state, you should try to use that instead of saveInstanceState.
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
andSharedPreferences
and take a look at here.The article covers three approaches:
Store local variable/UI control data for application lifetime (i.e. temporarily) using an instance state bundle
Store local variable/UI control data between application instances (i.e. permanently) using shared preferences
Keeping object instances alive in memory between activities within application lifetime using a retained non-configuration instance
Kotlin
You must override
onSaveInstanceState
andonRestoreInstanceState
to store and retrieve your variables you want to be persistentLife cycle graph
Store variables
Retrieve variables
This is a classic 'gotcha' of Android development. There are two issues here:
Browsing across all these threads, I suspect that much of the time developers are talking about these two different issues simultaneously ... hence all the confusion and reports of "this doesn't work for me".
First, to clarify the 'intended' behavior: onSaveInstance and onRestoreInstance are fragile and only for transient state. The intended usage (afaict) is to handle Activity recreation when the phone is rotated (orientation change). In other words, the intended usage is when your Activity is still logically 'on top', but still must be reinstantiated by the system. The saved Bundle is not persisted outside of the process/memory/gc, so you cannot really rely on this if your activity goes to the background. Yes, perhaps your Activity's memory will survive its trip to the background and escape GC, but this is not reliable (nor is it predictable).
So if you have a scenario where there is meaningful 'user progress' or state that should be persisted between 'launches' of your application, the guidance is to use onPause and onResume. You must choose and prepare a persistent store yourself.
BUT - there is a very confusing bug which complicates all of this. Details are here:
http://code.google.com/p/android/issues/detail?id=2373
http://code.google.com/p/android/issues/detail?id=5277
Basically, if your application is launched with the SingleTask flag, and then later on you launch it from the home screen or launcher menu, then that subsequent invocation will create a NEW task ... you'll effectively have two different instances of your app inhabiting the same stack ... which gets very strange very fast. This seems to happen when you launch your app during development (i.e. from Eclipse or Intellij), so developers run into this a lot. But also through some of the app store update mechanisms (so it impacts your users as well).
I battled through these threads for hours before I realized that my main issue was this bug, not the intended framework behavior. A great writeup and
workaround(UPDATE: see below) seems to be from user @kaciula in this answer:Home key press behaviour
UPDATE June 2013: Months later, I have finally found the 'correct' solution. You don't need to manage any stateful startedApp flags yourself, you can detect this from the framework and bail appropriately. I use this near the beginning of my LauncherActivity.onCreate:
To answer the original question directly. savedInstancestate is null because your Activity is never being re-created.
Your Activity will only be re-created with a state bundle when:
Android will destroy background activities when under memory pressure or after they've been in the background for an extended period of time.
When testing your hello world example there are a few ways to leave and return to the Activity.
In most cases if you're just pressing home and then launching the app again the activity won't need to be re-created. It already exists in memory so onCreate() won't be called.
There is an option under Settings -> Developer Options called "Don't keep activities". When it's enabled Android will always destroy activities and recreate them when they're backgrounded. This is a great option to leave enabled when developing because it simulates the worst case scenario. ( A low memory device recycling your activities all the time ).
The other answers are valuable in that they teach you the correct ways to store state but I didn't feel they really answered WHY your code wasn't working in the way you expected.