Concerning Android's Activity lifecycle, I've seen it widely claimed (on SO and elsewhere) that persistent data should be saved in the onPause() method, because there is no guarantee that onStop() will be called, since the OS may need to kill the activity to reclaim its resources if system resources are running low.
However, in a book I'm reading, the opposite is stated:
Practically speaking, the OS will not reclaim a visible (paused or
resumed) > activity. Activities are not marked as "killable" until
onStop() is called and finishes executing.
[Talks about stashed
state and activity record a bit]
Note that your activity can pass into the stashed state without
onDestroy() being called. You can rely on onStop() and
onSaveInstanceState(Bundle) being called (unless something has gone
horribly wrong on the device) ... Override onStop() to save any
permanent data, such as things the user is editing, because your
activity may be killed at any time after this method returns.
p70-71, Android Programming: The Big Nerd Ranch Guide, 3rd Edition
(emphasis mine)
Multi-Part Question:
Is this (possibility of an app being killed before onStop() is
called) something that is no longer true in and is still being
propagated, or is the book outright wrong?
Is there some nuance to when or why an Activity might be killed that
makes the answer "sometimes?"
If the book is correct, why is that misconception so widely spread? (E.g. Here, here, and here.)
References to official documentation would be appreciated.
This is an illustration of Activity lifecycle :
According to the official Android documentation,
onPause() execution is very brief, and does not necessarily afford
enough time to perform save operations. For this reason, you should
not use onPause() to save application or user data, make network
calls, or execute database transactions; such work may not complete
before the method completes. Instead, you should perform heavy-load
shutdown operations during onStop(). For more information about
suitable operations to perform during onStop(), see onStop().
There is a case when the app go from onPause() to onCreate() without onStop() and onDestroy() is when another app with higher priority needs memory as you see the illustration.
Also, The activity could be destroyed without calling onStart(),
onStop() when you call finish() method on onCreate() see reference
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 am trying to implement a 'resume' feature for a game I'm developing. It should work as follows:
If the user starts a game and later closes the game with finishing, the game state is saved. When opening the app again, a 'resume' option will be available.
If the activity is only paused (e.g. minimized due to a phone call) and the user returns, it should show the game in progress. It should not terminate and save the state, unless of course, the OS decides to kill the activity.
I've decided to use SharedPreferences for the most part, as well as a custom file to save extra information. I've seen a lot of people recommend saving the state of the program in the onPause() method and I've been wondering why this is the case.
From what I can gather, using OnDestroy() would be better. onPause() does not mean the activity will be killed so I could be wasting time when saving the game state necessarily. I've checked my program and onDestroy() is being called at the appropriate times. I'm assuming therefore I have no leak keeping the activity from being destroyed.
Despite this, I cannot find anywhere recommending to save state in onDestroy() and everyone seems to recommend using onPause. Am I missing a piece of information here?
Despite this, I cannot find anywhere recommending to save state in onDestroy() and everyone seems to recommend using onPause. Am I missing a piece of information here?
You are :). onDestroy() is not guaranteed to be called. See the documentation for it:
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here. This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
I have an activity in which I collect data for an online transaction. When the collection is done, I run a background thread (more specifically an AsyncTask) that calls a web-service and waits for its response, then return it to the activity. Meanwhile, a progress dialog shows up.
I want the background process to be cancelled if the application finishes or user cancels (however, I still need to notify the web-service), and retained if the activity is destroyed due to a configuration change or to free memory. I understand that I shall use onRetainNonConfigurationInstance() to detach my activity from the AsyncTask, retain it, and then reattach in the next activity, I already have the infrastructure for that. I also know that in some lifecycle callback, the isFinishing method tells me if my app is shutting down normally; and I do believe I can also handle the user cancel in the progress dialog's callback.
I have two simple questions:
Will onRetainNonConfigurationInstance() be called if my activity is
killed due to low memory? (I know it will be if the reason is a
configuration change.)
What is the situation (as emphasized by the developer guide) in which onStop() and onDestroy() are not called? (I want to know if my
code handling the cancellation would always execute.)
All in all, can I be sure that by implementing onRetainNonConfigurationInstance() and onDestroy() with isFinishing() checked, in every situation, my background thread will be handled accordingly?
BONUS question: If my application is killed for some reason (let's say permanently), how can I provide a way for the AsyncTask to save the response anyway? Can I retain an instance of shared preferences in it and write the data in that?
Will onRetainNonConfigurationInstance() be called if my activity is killed due to low memory?
No. Your activity is never individually killed for low memory. Your whole process may be terminated due to low memory, but onRetainNonConfigurationInstance() is only designed for in-process use.
What is the situation (as emphasized by the developer guide) in which onStop() and onDestroy() are not called?
Your process could be terminated due to low memory conditions (onStop() is very likely to still be called, but onDestroy() might not be if Android is in a hurry, such as due to an incoming phone call). Also, your app could crash with an unhandled exception. I am not certain if onDestroy() is called if the user force-stops you, but I doubt it.
All in all, can I be sure that by implementing onRetainNonConfigurationInstance() and onDestroy() with isFinishing() checked, in every situation, my background thread will be handled accordingly?
"Every" is a strong word. If Android terminates your process, your thread is gone as well.
If my application is killed for some reason (let's say permanently), how can I provide a way for the AsyncTask to save the response anyway?
Write the data to disk before doing anything else, and hope you are not killed before that point. Then, next time you run, notice that this saved data is floating around and arrange to do the rest of your work on it.
Could someone push me in the direction of some concrete, trustworthy (and preferably concise) information on the following:
The order in which components are destroyed and (where applicable)recreated by the system
(Fragment, Activity, Activity's Threads/AsyncTasks/Timers,
static data(when are classes unloaded?), Threads/AsyncTasks/Timers in other classes, host
TabActivity, ActivityGroup, bound local Services, Application, process)
both when the app is in the background, and in the foreground.
At which points the destruction can stop (what states can be encountered
upon return to the app - like "everything including the Application object
destroyed, process alive"?
Is it possible (without modifying Android) to programmatically cause the same kind of destruction
ourselves, so that it is indistinguishable from when the system does it, or is a separate mechanism needed for when we ourselves choose to free memory (triggered by onLowMemory)?
Reliable reproduction steps of all scenarios from 1) (would junit.framework do? I haven't investigated that) ?
"If the user leaves a task for a long time, the system clears the task of all activities except the root activity. When the user returns to the task again, only the root activity is restored": is this aside from the process/component lifecycle/destruction, or tied to it?
I have read various sources give pieces of information, often incomplete and misleading, sometimes incorrect.
I admit, I have skimmed over some parts of the documentation, so i may have missed or misunderstood something.
[EDIT] To avoid misunderstandings: What I am asking about is Android destroying components to free memory, bypassing Activity.onDestroy.
When I put the app in the background and return later, the one of these sequences will occur:
onPause, onStop, onRestart, onStart, onResume
onPause, onStop, Application.onCreate, onCreate(notNull), onStart, onResume
[EDIT2]
Bounty started. Need reliable info on: Activities, Fragments, Application, bound (potentially remote)Services, process.
Partial/full destruction scenarios. See 1st point.
This is what my experience, and that of devs I've asked, seems to suggest:
Fragments are not autodestroyed.
non-visible Activities on the app's stack can be autodestroyed in any order, and in any number.
destroyed Activity's (or any other class's) Threads and statics remain untouched until Application is destroyed.
TimerTasks: haven't tested.
bound local Services: destroyed somewhere between the destruction of the last binding Activity and of Application.
Application is the last thing to go within a process, and "goes" along with all Threads.
the process can exist for a long (20+ minutes) time after the destruction of the Application object, unless you have an automatic task killer.
Activities under TabActivity or in ActivityGroups are not autodestroyed, but go all at once if the container is destroyed.
Example: a TabActivity with ActivityGroups under tabs. All Activities live. Another Activity is started, fullscreen. The TabActivity with everything in it is now eligible for destruction by Android, all at once or not at all.
NO.
If you destroy an Activity manually, it goes through the entire lifecycle and doesn't pass a Bundle to onCreate when started again.
Also, onLowmemory is unreliable - even with small allocation steps, it might never be called before OutOfMemoryError is thrown.
NO.
Despite the autodestruction/restoration being such a major feature in Android, there isn't any way to test such scenarios.
This is probably related only to whether the process still exists or not. If it does, Android will attempt to restore the old Activities. If not, it's a clean restart.
The above include some assumptions.
I am still waiting for someone to confirm it and supply some docs (guarantees not dependent on the current implementation of classes).
Please, PLEASE correct me if any of this is wrong.
Edit: The above information may be out of date, it was tested on Android 2.1-2.3
Credit for this goes to hackbod for writing it here(read the whole answer), and to CommonsWare for linking in a comment.
In short: All the docs, rewritten many times, continue to lie to us. They're not misleading, they just give us untrue information. Unless you're using Fragments (dunno if support v4 counts, too), Android frees memory by killing the whole process, or does nothing.
Of course, this does not address everything:
Point 4 of the question
Why I frequently saw onCreate(notNull) on pressing Back on an Activity stack with Activities handling all config changes (Android 2.3.7)
How this relates to the widely accepted belief that onPause is the last call you are certain to get, and onStop may never get called (how, then, can the app go to the background, to be killed?)
We're getting somewhere, though.
Well, my friend,
I guess you'll have a lot of trouble in your research. Basically because you're talking about two black boxes: the Dalvik garbage collector and the android heap manager. I would say that you cannot trust that android will follow any order of object destruction. But, you can trust that this lifecycle is going to be followed [Programming Android, 2011]:
Activity Lifecycle:
onCreate() - Called after the instance of the activity has been created for the first time
onRestart() - Called after an activity has been interrupted, just before the onStart();
onStart() - Called when the object activity and their visions become visible to the user;
onResume()- Called when the object activity and their visions become interactive to the user;
onPause() - Called when a different instance of the activity is going to get visible and the present activity ceases to interact with the user
onStop() - Called when the activity is no longer visible or is not interacting
onDestroy() - Called when an activity instance must be destroyed and it's no longer needed.
Fragments have different lifecycles including methods onAttach, onCreateView and onActivityCreated .
But, why do you care about the objects order of destruction? I can't see no reason for you to monitor such events, but if you really need, learn more about the garbage collector.
The ActivityManagerService#trimApplications()method remove any unused application processes if the application's current receiver is null, does not have any activity and service.
When it comes to activities, they will be only destroyed on on Destroy() until and unless developer manually calls the finish() function,
Fragment life cycle is a completely matched to its parent activity, so when parent activity destroys on on Destroy(), the fragments on Destroy() as well will be called.
Timer Tasks will finish their work and become candidates for garbage collection, once the activity creates them the task runs in its own thread, no relation with activity, even if the activity is destroyed, the task finishes itself....
This is not a complete answer but what I would recommend is that you place toast messages in each of these methods. Add in your own onPause(), onStop(), onResume(), etc. and inside put a line like this:
Toast.makeText(this, "onPause()", Toast.LENGTH_SHORT).show();
You cannot directly call these methods, however moving another activity to the top of the stack will of cause these methods on the existing activity to be called. One more thing to keep in mind is that onCreate() need not be called every time you start an activity. It really depends on how you start the activity, for example if you send this intent
Intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_SINGLE_TOP);
it will appear call onNewIntent() instead if it has already been created. In summary the best thing is just to watch the Toast messages. Also you really need to focus on using the debugger. Place a breakpoint on each method and you can see it. One thing I am sure of is that you cannot directly invoke these methods like onPause(). Also keep in mind that in general you don't know when onDestroy() will be called.