76

This is my savedInstaceState code:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) 
{
    savedInstanceState.putStringArrayList("todo_arraylist", Altodo);
    Log.v("bundle", "Saved");
    super.onSaveInstanceState(savedInstanceState);
}


public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) 
    {
        Altodo = savedInstanceState.getStringArrayList("todo_arraylist");
        Log.v("bundle", "Restored");
    }
    else
    {
        Log.v("bundle", "null");
    }

    setContentView(R.layout.main);
}

The logs always show the "bundle save" tag.

But in onCreate method, SavedInstanceState is always null.

Alexander Farber
  • 18,345
  • 68
  • 208
  • 375
med
  • 1,450
  • 1
  • 14
  • 26
  • 2
    you need to call super.onSaveInstanceState(savedInstanceState) before adding your values to the Bundle, or they will get wiped out on that call (Droid X Android 2.2). – AndroidGeek May 29 '14 at 06:24
  • 2
    I am having the same problem and can confirm that this doesn't work. Anyone solved it already? – Jim Clermonts Jul 29 '14 at 08:29

13 Answers13

56

I observed the exact same symptoms (reported as issue 133394) in a project with two Activities A and B that extend ActionBarActivity. Activity A is the main activity, and I always receive null for savedInstanceState in onCreate of its list fragment when returning from a detail view activity B. After many hours, this problem exposed itself to me as a navigation issue in disguise.

The following may be relevant to my setup and come from other answers on this page:

  • Given this answer, I made sure that fragment and activity each have unique IDs set.
  • There is no override of onSaveInstanceState without super call.
  • Activity A is specified as acitivy B's parent in AndroidManifest.xml, using both the android:parentActivityName attribute and the corresponding meta-data tag for earlier versions of Android (see "Providing Up Navigation").

Already without any corresponding creation code such as getActionBar() .setHomeButtonEnabled(true), activity B has a functioning back button (<) in its action bar. When this button is tapped, activity A reappears but with (a) all previous instance state lost, (b) onCreate always called, and (c) savedInstanceState always null.

Interestingly, when I tap the back button provided at the bottom edge of the emulator display (an open triangle that points to the left), activity A reappears just as it was left (i.e. its instance state fully retained) without invoking onCreate. So maybe something is wrong with navigation?

After more reading, I implemented my own navigation instructions to run in response to a tap on the back-button in activity B:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == android.R.id.home)
        NavUtils.navigateUpFromSameTask(this);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Nothing related to restoring instance state of activity A changed. NavUtils also provide a method getParentActivityIntent(Activity) and navigateUpTo(Activity, Intent) that allow us to modify the navigation intent to explicitly instruct that activity A is not started fresh (and thus without saved instance state provided) by setting the FLAG_ACTIVITY_CLEAR_TOP flag:

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.

In my hands, this solves problem of lost instance state and could look like:

public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId()== android.R.id.home) {
        Intent intent = NavUtils.getParentActivityIntent(this);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        NavUtils.navigateUpTo(this, intent);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Note that this may not be the complete solution in other cases where a user can switch directly to activity B from within a different task (see here). Also, a possibly identical solution in behavior that does not make use of NavUtils is to simply call finish():

public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId()== android.R.id.home) {
        finish();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Both solutions work in my hands. I am only speculating that the original issue is a slightly incorrect default implementation of the back-button, and it may be related to that implementation invoking some kind of navigateUp that misses FLAG_ACTIVITY_CLEAR_TOP.

Community
  • 1
  • 1
s.bandara
  • 5,553
  • 1
  • 19
  • 36
  • 1
    Awesome. I implemented it into my base activity using the last solution you provided, however I replaced `finish();` with `onBackPressed();`. – Andrea Lazzarotto Aug 22 '16 at 13:35
  • 2
    This answer helped me a lot! I am still not sure why the Action Bar back button was behaving differently than the device back button, but once I added `android:launchMode="singleTop"` to my Activity's XML definition in AndroidManifest.xml, it started working consistently. According to docs, this is essentially the same as adding `FLAG_ACTIVITY_CLEAR_TOP`as you had done. – JHS Sep 18 '17 at 02:35
  • Is it efficient to be calling `finish();` every time you launch another activity? Is there any better options? – Elijah Mock Jan 08 '20 at 02:44
  • 2
    2020 And I'm still hitting this bug. Ridiculous. Google ignored that issue 133394 for 5 years, until Apr. 2020, and then closed it "as won't fix obsolete". Thanks for the comprehensive answer; that last onOptions...finish() blob fixed it for me. It looks like yours is going to be the only fix for quite some time. Thanks again, you saved me after days of my pulling hair out. – Yurelle Aug 19 '20 at 02:58
14

Did you check if you have an Id set for that view ( if a view it is/has...). onSaveInstanceState() is not called otherwise.

Check this link.

Community
  • 1
  • 1
PHF
  • 1,553
  • 12
  • 18
  • 3
    This answer seems unrelated to the problem asked. Med stated that onSaveInstanceState() is always called, so the problem is not about onSaveInstanceState() not being called – P1x Mar 05 '16 at 17:58
13

The state saved in this manner is not persisted. If the whole application is killed as you are doing during debugging, the bundle will always be null in onCreate.

This IMO is yet another example of awful Android documentation. It's also why most apps in the marketplace don't implement saving state properly (at all).

mxcl
  • 24,446
  • 11
  • 91
  • 95
  • 2
    So this is just for screen-orientation changes etc.? – Fabian Zeindl May 27 '13 at 13:40
  • 7
    I wholeheartedly agree with "awful documentation" btw. – Fabian Zeindl May 27 '13 at 13:40
  • 1
    Fabian, the saved state will still in theory be created when the activity is destroyed and then recreated, it's just impossible to test this eventuality. IME this use-case *does* occur. – mxcl May 27 '13 at 13:47
  • I know. My first thought when reading about Bundle, though, was that it's the primary/default/simplest way of storing the state off an application. Not that it's used in "edge-cases". – Fabian Zeindl May 28 '13 at 15:54
  • 3
    It looks like a bug, because the documentation explicitely says that the state is saved even when destroying activities http://developer.android.com/guide/components/activities.html#SavingActivityState I created the issue https://code.google.com/p/android/issues/detail?id=133394 – Simon Feb 04 '15 at 12:11
  • The state isn't saved when the task is killed (when you swipe away the app in the task switcher), but it is kept when the Activity is destroyed (when rotating or if you haven't used the app in a long time). You can simulate destroying activities by setting `Don't keep activities` in Developer options to on. With this on, switching away from you app then back to it will cause you Activity to be restarted. (@mxcl this is how it is possible to test.) – Jade Jun 28 '16 at 20:15
  • How do we save persistent state then? – David Callanan Nov 23 '19 at 18:51
8

in Manifest add this line for activities

android:launchMode="singleTop"

for example:

<activity
        android:name=".ActivityUniversity"
        android:label="@string/university"
        android:launchMode="singleTop"
        android:parentActivityName="com.alkhorazmiy.dtm.ActivityChart">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.alkhorazmiy.dtm.ActivityChart" />
    </activity>
Al Khorazmiy
  • 106
  • 1
  • 1
  • 1
    What exactly does specifying this line do for an activity? – David Read Apr 20 '20 at 00:26
  • @DavidRead late reply but, marking activity as `singleTop` makes it such that, if there's an existing activity in background it is used. `If, when starting the activity, there is already an instance of the same activity class in the foreground that is interacting with the user, then re-use that instance. This existing instance will receive a call to onNewIntent() with the new Intent that is being started.` You just have to override `onNewIntent()` afterwards in the activity. With `onResume` my uri was null with `standard`, and `singleInstance` recreated it due to process death. – CyberShark Apr 17 '21 at 13:32
3

How do you test it?

Imo the best way to test it is using the "Don't keep activities"-flag in Settings > Developer Options. If you don't have Developer Options in Settings, see Enabling On-device Developer Options.

  1. Open your activity
  2. Long-press home
  3. Go to another application
  4. Long-press home
  5. Go back to your application
Jade
  • 2,947
  • 1
  • 31
  • 41
mibollma
  • 14,347
  • 6
  • 44
  • 65
  • DevTools only work in the emulator. If you want to test on a real device using the same method, use the SetAlwaysFinish tool. See this answer for more details: http://stackoverflow.com/a/8621269/483708 – Theo Dec 24 '11 at 00:29
  • Developer Options is now available on all devices. – Jade Jun 28 '16 at 20:35
2

Shouldn't super.onSaveInstanceState(savedInstanceState); be the first line in your override?

Edit: War_Hero points out in the comments that the documentation on that topic indicates that no, it shouldn't be the first line.

Jonathan Allard
  • 16,498
  • 10
  • 52
  • 72
1

Check your activity in AndroidManifest.xml and remove android:noHistory property if is true.

<activity
    // ....
    android:noHistory="false" />
Reaz Murshed
  • 21,071
  • 12
  • 69
  • 87
0

I found that when I override onSaveInstanceState() and actually save some data in the Bundle, instance state is restored. Otherwise it's not.

Aron Lorincz
  • 1,607
  • 3
  • 20
  • 28
0

Ive managed same way arround. Instead of handling savedInstanceState Bundle on the onCreateView method, ive handled it on onCreate method and setting the passed value to a globar variable then acessing this variable on the onCreateView method. Hope it helps.

0

https://developer.android.com/guide/topics/manifest/activity-element#lmode

From this you can see 'Similarly, if you navigate up to an activity on the current stack, the behavior is determined by the parent activity's launch mode.' Maybe you are in the 'standard' mode.

0

I was able to solve it with:

@Override public boolean onSupportNavigateUp()
{
    onBackPressed();
    return true;
}

still had parent set in the manifest. So when you press the up navigation button, now it acts like the back button.

Chuck
  • 159
  • 1
  • 7
0

To debug, consider implementing onRestoreInstanceState and placing a call to Log.d in this method. Then, in the emulator, hit ctrl-F11 or whatever to rotate the phone. Your call to Log.d should be hit.

JAL
  • 3,289
  • 2
  • 18
  • 17
  • 1
    i have changed log.v to log.d but it never hits. – med Jul 02 '11 at 11:53
  • @med your situation may be more complex than we understand if in a single activity onRestoreInstanceState is not called on orientation change. I have some code here: https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/saving-instance-state – JAL Jul 02 '11 at 18:23
0

Implement a method of onRestoreInstanceState and put below code there

Altodo = savedInstanceState.getStringArrayList("todo_arraylist");
Dharmendra
  • 31,033
  • 22
  • 83
  • 126
  • i have tried.i got the same problem here:http://stackoverflow.com/questions/4096169/onsaveinstancestate-and-onrestoreinstancestate – med Jul 02 '11 at 13:45