Reputation: 13287
My app is running on a special device that is running a custom build of Android Gingerbread 2.3.7
There are conditions where the system will terminate my app. I assume that the device manufacturer considers these emergency situations where all third party apps should be immediately shut down so the device can do its primary tasks.
I can duplicate the behavior I see on the device using an emulator and in DDMS selecting my task and clicking the "Stop Process" button. Here is the behavior I see.
My app typically steps through four activities, Activity A launches activity B, B launches Activity C, and C launches activity D. So, when activity D is running on top, my stack is:
A - B - C - D
If at this point, the process is terminated, Activity D does not receive onPause() or an onStop() call. It has no opportunity to save its state.
After the process is dead, Android's ActivityManager starts a new task for my app and launches Activity C. I think this is standard Android behavior to restart crashed apps.
My question is can I control this restart behavior? If Android is going to restart my app, I need the activity stack restored, Activity C doesn't really make sense to be run stand alone (clicking the back button would exit the app and that doesn't make sense for this activity).
Can I prevent this restart? Can I have the restart start all my activities in sequence? Can I have the restart just start activity A?
I did find this interesting discussion which I believe explains why Activity C is restarted and not Activity D.
As far as when an activity is restarted -- if the process running the foreground activity goes away, the system will throw away that activity if it does not have a valid saved state for it (typically meaning it is paused and has given the system the result of onSaveInstanceState from before the pause). Once it has decided whether or not to throw away that activity, it will resume whatever activity is now at the top of the stack. If this is one of your activities -- either because you have another behind the one that crashed, or the one that crashed was somehow it the settled pause state -- then it will start your process again to show that top activity.
And some similar questions like Prevent Activity Stack from being Restored? and this interesting thread
Upvotes: 6
Views: 5907
Reputation: 13287
After a lot of experimenting, I opted for the approach hinted at in "Android Developers › Activity restart crash after OS kills it". One Q/A interchange there was:
Question:
"have stepped through the code and have seen what you are talking about. It calls onSaveInstanceState and saves the data in the Bundle. Will this Bundle information be available when the activity restarts after the OS kills the process?"
Answer:
"It's supposed to. You will get that Bundle in onCreate() and in onRestoreInstanceState(). onCreate() can be passed null for the Bundle, if there is no Bundle to restore. onRestoreInstanceState() is only called when there is a Bundle to restore."
I moved all the session data needed to recover after the app is killed into a serializable singleton.
In onSaveInstanceState() I put the serialized session data in to the savedInstanceState bundle
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// save and restore session data to instance state to recover from task termination
savedInstanceState.putSerializable(SessionVariables.class.getName(), mSessionVariables);
}
In onCreate() and onRestoreInstanceState() I test to see if my session singleton instance is valid. If it doesn't have valid data, I restore the session variables from the savedInstanceState bundle and put this restored object as my session variable singleton.
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (mSessionVariables.propertyThatShouldbeGood == null || mSessionVariables.propertyThatShouldbeGood .length() == 0)
{
// save and restore session data to instance state to recover from task termination
Serializable serializedSessionVariables = savedInstanceState.getSerializable(SessionVariables.class.getName());
if (serializedSessionVariables != null) {
mSessionVariables = (SessionVariables) serializedSessionVariables;
SessionVariables.putInstance(mSessionVariables);
}
}
}
Now when my task is killed, Android restores the previous activity from the stack. The onCreate() restores all the necessary session data from the saved instance state bundle.
The Back button also works fine at this point, so I was wrong Android not preserving the Activity stack. I think it just restores the back activities as needed (when you navigate back). If you don't navigate back, it doesn't create them. At least that is what it looked like in HierarchyViewer.
When my stack is A-B-C-D and the task is killed, Activity "C" is restored and "D" is lost. But, now "C" is in a healthy state and the user can easily navigate back to "D". Now, I could also start the "D" activity automatically from "C", I just haven't had time yet.
Upvotes: 5