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)
Related
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.
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
Through Android's Activities doc, it is said that the methods onStop() and onDestroy() are not guaranteed to be called.
[...] once the activity is created, onPause() is the last method that's guaranteed to be called before the process can be killed—if the system must recover memory in an emergency, then onStop() and onDestroy() might not be called [...]
I would like to know, when this situation occurs, is the app also killed within the activities or just the activity itself is killed?
Answer is app process is also get killed and can be recreated.
https://developer.android.com/training/basics/activity-lifecycle/recreating.html
Please check http://www.vogella.com/tutorials/AndroidLifeCycle/article.html
Application with only stopped activities and without a service or executing receiver. Android keeps them in a least recent used (LRU) list and if requires terminates the one which was least used.
I'm new to android system and its related things, I want to know when android removes existing instances of activities and their related bundle and data. And also where those instance are stored in android system?
Edit:
Let's say I start an activity and then return to home screen and not back to stopped activity for many hours. How long android will keep all these existing instances and when removes them?
Android maintains a stack system for storing the activities.
A -> B -> C
Your activity could be destroyed upon pressing the home button if the system is constrained and has determined it needs to free some resources.This only occurs if Android terminates the process. Android does not destroy individual activities in response to memory pressure. The documentation states that onDestroy() can be called if:
This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
You can't determine when it will be destroyed, it's decided by the system when it needs memory so it just kills your app. It's just like GC call, you can never determine when it'll be called, it's controlled by the JVM, similarly this is controlled by the kernel.
Note : The system can kill your program without calling onDestroy() after onStop() has been called. Therefore, any cleanup/data persistence code should be in either onPause() or onStop().
I'm confused why anyone would ever override Activity.onDestroy() instead of onPause() if according to the documentation:
There are situations where the system will simply kill the activity's
hosting process without calling this method (or any others) in it,
I see much code that overrides onDestroy() despite this warning. Why?
Why override Activity.onDestroy() if it isn't reliably called?
It's not that it isn't reliably called... it's just that it isn't the only way the Activity can be killed. The Android system might trash your entire process without giving the ActivityManager the chance to call onDestroy() if your device begins to lack memory resources.
For this reason, you shouldn't ever rely on onDestroy() being called, and you should always save persistent state in onPause.
Objects held by the activity will get destroyed if the process is killed directly. If the process is not killed (and onDestroy() is called) then you will have to manually release the objects if needed. E.g, when the process is killed, a Cursor will be destroyed, but if the process is not destroyed and you repeatedly enter the activity there will be resource leakage.