I'm testing that my app is able to recover from unexpected situations that lead the OS to kill my app's process due to different circumstances like low memory. To do this, I've enabled "Don't Keep Activities" in Developer Options.
I'm attempting to restore the app's state by saving state values in the Activity's Bundle through the lifecycle method onSaveInstanceState, but after setting breakpoints I've noticed that onSaveInstanceState does not get called.
Question:
Am I wrong in expecting onSaveInstanceState to be called in this scenario or might there be other factors that are preventing the method to fire? If neither, what else can I do to recover the state in this scenario?
I think two possibilities are supposed.
Your scenario is wrong
The official reference says:
Do not confuse this method with activity lifecycle callbacks such as
onPause(), which is always called when the user no longer actively
interacts with an activity, or onStop() which is called when activity
becomes invisible. One example of when onPause() and onStop() is
called and not this method is when a user navigates back from activity
B to activity A: there is no need to call onSaveInstanceState(Bundle)
on B because that particular instance will never be restored, so the
system avoids calling it. An example when onPause() is called and not
onSaveInstanceState(Bundle) is when activity B is launched in front of
activity A: the system may avoid calling onSaveInstanceState(Bundle)
on activity A if it isn't killed during the lifetime of B since the
state of the user interface of A will stay intact.
If your scenario is a 'no need to call' case, onSaveInstanceState won't be called.
Your breakpoints are wrong
If called, this method will occur after onStop() for applications
targeting platforms starting with Build.VERSION_CODES.P. For
applications targeting earlier platform versions this method will
occur before onStop() and there are no guarantees about whether it
will occur before or after onPause().
So the timing of onSaveInstanceState called depends on your targeting platform.
An easy workaround is to backup data with SharedPreference, etc. in onPause.
Related
Android documentation about Activity says that onDestroy may not get called if the system kills your process to reclaim memory.
My questions are
Is there a way (developer tool etc) to simulate this situation (no onDestroy) for testing?
Suppose my process is killed by the system to reclaim memory and user navigates back to my activity, what methods are called? Does onCreate get called again?
onDestroy simply isn't guaranteed to be called. In both situations everything has to be created again... so onCreate, onStart etc. You don't need a tool - if its some code that MUST run, don't put it there. https://developer.android.com/reference/android/app/Activity.html#onDestroy%28%29
I am not clear on what the situation is when an activity is "destroyed" by the OS.
Let me explain why - in the diagram of the activity lifecycle here: http://developer.android.com/reference/android/app/Activity.html
There is an arrow going directly from onStop() to 'App process killed' then an arrow from 'App process killed' to OnCreate().
This diagram therefore shows that onDestroy() is NOT called if the OS kills the activity due to memory constraints etc.
However in the description of the lifecycle the word "destroy" is used many times. For example the following quote from this page: http://developer.android.com/training/basics/activity-lifecycle/recreating.html
The system may also destroy your activity if it's currently stopped
and hasn't been used in a long time or the foreground activity
requires more resources so the system must shut down background
processes to recover memory.
So the documentation is saying the activity is destroyed yet in the diagram the arrow goes from onStop() to onCreate() and bypasses onDestroy(). This is why I am confused as it is apparently a contradiction.
If I have an activity which creates some objects in its onCreate() method and I set them to null in onDestroy() but onDestroy() is not called if the app moves from onStop() to onCreate() then won't I have a memory leak as they will get created again in onCreate()?
I can't set them to null in onStop() because then if the lifecycle moves from onStop() to onRestart() to onStart() they will be null.
Therefore how does one deal with the correct sequence of creating and destroying of child objects within an activity in order to deal with all paths in the lifecycle diagram?
Is it necessary within onCreate() to only create the objects if they are null and not otherwise?
This diagram therefore shows that onDestroy() is NOT called if the OS kills the activity due to memory constraints etc.
The arrow in question is labeled "Apps with higher priority need memory". Hence, this diagram shows that onDestroy() is not called if the OS terminates the process because apps with higher priority need memory. Android will terminate the app's process more gently in other cases, and in those cases, Android will take the time to call onDestroy() on your activities. onDestroy() is also called in other scenarios, such as finish(), the default behavior of the BACK button, the default behavior on a configuration change, etc.
If I have an activity which creates some objects in its onCreate() method and I set them to null in onDestroy() but onDestroy() is not called if the app moves from onStop() to onCreate() then won't I have a memory leak as they will get created again in onCreate()?
No, because the whole process is terminated "if the app moves from onStop() to onCreate()". Android does not destroy individual activities due to low memory conditions, despite some statements in the documentation to the contrary.
Therefore how does one deal with the correct sequence of creating and destroying of child objects within an activity in order to deal with all paths in the lifecycle diagram?
Lots of things should be cleaned up in or before onStop(). Specifically, anything that you're doing that may cause the user to regret having installed your app, such as requesting GPS fixes, should be considered for cleanup in onPause() or onStop().
For those things that you determine properly should be cleaned up in onDestroy(), do so. AFAIK, there are only three possibilities:
You are called with onDestroy() and can do your cleanup work
Your process is terminated, in which case your cleanup work is no longer needed or possible
You crashed with an unhandled exception, in which case Android is not guaranteed to call any more lifecycle methods (moral of this story: use good exception handlers)
I have an activity and I have a fragment stack in it and sometimes, this stack get's lost... Although I save and restore it...
I know following:
onSaveInstanceState is not called:
a) if the user navigates back, which makes sense...
b) if the activity is finished
onSaveInstanceState is called:
a) on screen rotation
I discovered through debugging, that I can't be sure, if onSaveInstanceState is called, if screen turns black...
My app is an app, that you use for logging, meaning, you put your phone aside and come back every now and then and fill out your log... So sometimes, my activity is recreated with an empty bundle and onSaveInstanceState was not called, although my app was in the foreground and only the screen turned off...
Questions
1) what can I do to solve that problem? Do I really have to save my fragment states and the stack persistantly?
2) on screen rotation, I can be SURE that onSaveInstanceState is called, can I? Are there any other circumstances, where I can rely on onSaveInstanceState?
1) Im reffering to this thread: android life cycle you should use onPause() because you can't be sure if the app is just paused or beeing killed.
2) from developer.android.com ( Activity)
Be aware that these semantics will change slightly between
applications targeting platforms starting with HONEYCOMB vs. those
targeting prior platforms. Starting with Honeycomb, an application is
not in the killable state until its onStop() has returned. This
impacts when onSaveInstanceState(Bundle) may be called (it may be
safely called after onPause() and allows and application to safely
wait until onStop() to save persistent state.
I seem to have the opposite problem to everyone else. :)
My onSaveInstanceState is getting called whenever I navigate from one activity to the next.
I checked in LogCat and it is definitely NOT killing the activity.
Also, I see that the onRestoreInstanceState is not called when returning so it must have still been in memory.
I thought it was only called when freeing up memory or during orientation changes.
Yes, onSaveInstanceState() is called when the activity is paused. This is because once the activity is paused, Android can kill the process at any time time (without calling any other lifecycle methods). If the activity is resumed before the process is killed, Android realizes that it doesn't need to call onRestoreInstanceState() so it doesn't make that call (this is an optimization).
What about the doc saying;
"If called, this method will occur before onStop(). There are no guarantees about whether it will occur before or after onPause()."
The documentation on onSaveInstanceState() states:
If the method is called, it is always called before onStop() and possibly before onPause().
But, I notice, consistently, from log messages that onPause() is ALWAYS CALLED BEFORE onSaveInstanceState(). I had put log messages in these two methods. Please help me understand in what circumstances does onSaveInstanceState() is called before onPause().
Environment: Android v4.0 (API 14) + Eclipse v3.7.1 - Indigo.
You can read about that here.
In a nutshell you can't never know about time when onSaveInstanceState will be run.
Please help me understand in what circumstances does
onSaveInstanceState() is called before onPause()
There is a difference in the Activity lifecycle between the pre-HONEYCOMB and the other platforms (since HONEYCOMB onwards):
API level >= 11: when onPause() is called, the process is in a safe state, it can't be killed.
API level < 11 : when onPause() is called, the process that hosts the Activity becomes killable. It means that the system can kill the process, that contains the activity, without executing any other line of code. So if this happens the onSaveInstanceState() may never be called. In order to avoid this, the system should call onSaveInstanceState() before onPause(), otherwise you will not able to save the user state.
onSaveInstanceState() is nice, but only guaranted callback is onPause(), called when your activity loses focus. So, save your state there