Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intent not restored correctly after activity is killed if clear top and single top flags are supplied

In my application there is an activity started using the FLAG_ACTIVITY_SINGLE_TOP and FLAG_ACTIVITY_CLEAR_TOP flags because I want to make sure that only one instance of that activity is at the top of the stack and all activities on top of the old instance are closed. So far so good.

Next I wanted to test if the activity restores correctly after being created more than once and successively destroyed. I take care to manually set the intent using Activity.setIntent() when Activity.onNewIntent() is called so that the most recent intent is returned by Activity.getIntent(). In order to test that I activated the "Don't keep activities" option in the developer options, but the intent returned by Activity.getIntent() when the activity is re-created is the very first intent that created it and not the most recent one.

This happens on JB and ICS, I haven't tested it on older versions. Am I doing something wrong or did I misunderstand something in the docs?

like image 407
futtetennista Avatar asked Feb 13 '13 12:02

futtetennista


People also ask

When a new activity comes on top of your activity completely then what is the life cycle function that gets executed in the Old activity?

onStop(): Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed.

Is onDestroy called when app is killed?

onDestroy() is called before the activity is destroyed. The system invokes this callback either because: the activity is finishing (due to the user completely dismissing the activity or due to finish() being called on the activity), or.

How do you retrieve data which is send from an intent?

This Intent object can be retrieved via the getIntent() method. The component which receives the intent can use the getIntent(). getExtras() method call to get the extra data.

What is Flag in intent?

Use Intent FlagsIntents are used to launch activities on Android. You can set flags that control the task that will contain the activity. Flags exist to create a new activity, use an existing activity, or bring an existing instance of an activity to the front.


2 Answers

If you kill your app while it is in the foreground, this is not the same as when Android kills your app (which it will only do when your app is in the background). If you kill and then restart the app, it is like starting it all over again from scratch. There is no "restore" going on here. If you add logging to onCreate() you should see that after you kill and restart your app, the Bundle that is passed to onCreate() is null.

Unfortunately it is pretty difficult to simulate what happens when Android kills your app.

EDIT: Added more stuff after OP's comment

Here's a concrete example for discussion purposes. First without the developer option "Don't keep activities":

  • ActivityA is the root activity
  • We start ActivityA
  • ActivityA.onCreate() is called
  • ActivityA now starts ActivityB
  • ActivityB.onCreate() is called (The activity stack now contains ActivityA->ActivityB)
  • ActivityB starts ActivityA with FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP and an extra "foo"
  • ActivityA.onNewIntent() gets called with the Intent containing FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP and an extra "foo"
  • ActivityB.onDestroy() is called since the activity stack was cleared back to ActivityA

Now, let's do the exact same thing but enable the developer option "Don't keep activities" (I've highlighted in bold the stuff that is different from the previous scenario):

  • ActivityA is the root activity
  • We start ActivityA
  • ActivityA.onCreate() is called
  • ActivityA now starts ActivityB
  • ActivityB.onCreate() is called (The activity stack now contains ActivityA->ActivityB)
  • Because ActivityA has stopped, Android destroys it and calls ActivityA.onDestroy()
  • Note: The activity stack still contains ActivityA->ActivityB, even though there is no instance of ActivityA at the moment. Android remembers all the state
  • ActivityB starts ActivityA with FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP and an extra "foo"
  • Since Android has no instance of ActivityA to reactivate, it needs to create one, so it does and then...
  • ActivityA.onCreate() is called with the same Intent that it was called with when the original instance of ActivityA was created (ie: LAUNCH intent with no flags and no extras)
  • ActivityA.onNewIntent() gets called with the Intent containing FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP and an extra "foo"
  • ActivityB.onDestroy() is called since the activity stack was cleared back to ActivityA

The important thing to note here is that Android always calls onCreate() whenever it creates an activity instance. Think of it like the constructor of an Activity. If Android has to recreate an instance of an Activity because the process was killed or the activity was destroyed, then it will instantiate a new object, then call onCreate() and then (if necessary) it will call onNewIntent().

When you call setIntent() this doesn't actually change the Intent that Android saves and restores. That only changes the in-memory Intent that will be returned from a call to getIntent().

I hope this is clearer now. If not, please let me know.

like image 69
David Wasser Avatar answered Sep 28 '22 00:09

David Wasser


Not sure if you've found a solution to this or not, but overriding the onNewIntent(Intent theNewIntent) method for the target activity & calling setIntent(theNewIntent) solved it for me.

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);

    /*
     * This overrides the original intent.
     */      
    setIntent(intent);
}
like image 26
Ryhan Avatar answered Sep 28 '22 01:09

Ryhan