When I read Android Training , I saw a description for the activity-lifecycle:
When your activity is stopped, the Activity object is kept resident in
memory and is recalled when the activity resumes. You don’t need to
re-initialize components that were created during any of the callback
methods leading up to the Resumed state. The system also keeps track
of the current state for each View in the layout, so if the user
entered text into an EditText widget, that content is retained so you
don't need to save and restore it.
I'm confused, if I don't need to re-initialize any components, why do I have to handle data or any something on callback method?
Just take Camera as an example.
You don't need to reinitialize any component, but you need to reinitialize the camera when the activity resumed. Component arne't the only part of an activity. Most applications also need to access system resources. You release these resources when your application gets paused or stopped, so you must reinitialize them again when your application is resumed. And Android may destroy your application in some circumstances (memory not enough, etc.) So you have to release and reinitialize resources again.
Moreover, there might be some internal state of your application. For example a book reader. You need to record the progress. This internal state are not components but you have to save them when your activity get paused.
#Override
public void onPause() {
super.onPause(); // Always call the superclass method first
// Release the Camera because we don't need it when paused
// and other activities might need to use it.
if (mCamera != null) {
mCamera.release()
mCamera = null;
}
}
#Override
public void onResume() {
super.onResume(); // Always call the superclass method first
// Get the Camera instance as the activity achieves full user focus
if (mCamera == null) {
initializeCamera(); // Local method to handle camera init
}
}
That description applies only to the stopped state. A stopped activity can also be destroyed, so the idea is that you save your data in onStop() in case the activity is subsequently destroyed. While there is an onDestroy() callback, it is not guaranteed to be called. onStop() can be relied upon to be called when your activity transitions from paused to stopped.
Note that in pre-Honeycomb versions of Android even onStop() can't necessarily be relied on, and onPause() should be used to save state. Honeycomb and subsequent versions will not kill an activity until the onStop() method has returned.
If your activity is stopped (ie the user presses home OR he handles an incoming call), the process (and the contained activity) of your application is not destroyed.
In this scenario, your components are already initialized (that means, they are showing what they were showing before your activity was stopped) and when the activity is brought to front again (the user reopens your app), you don't have to restore any sort of data.
However, after a while, the os may decide to reclame your app's resources and decide to kill the process (or the user may press back button from your home activity). In this other scenario, you are supposed to save the state of your activity in order to restore it whenever the user gets back to your app.
You can use onSaveInstanceState
or just store to preferences on onStop()
Related
I have the following security requirement for my app :
Verify that the app removes sensitive data from views when backgrounded.
My question is, Does Android remove data from views when backgrounded ?
What i know as per android documentation is that :
By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text value entered into an EditText widget).
One solution is that i can clear all views then use below approach to save state
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
} else {
// Probably initialize members with default values for a new instance
}
// ...
}
But i have no idea of whether Android os clears data in views.Any help will be appreciated.
Thanks
Android does not automatically recycler your view as soon as your application moves to background.
The system kills processes when it needs to free up RAM; the likelihood of the system killing a given process depends on the state of the process at the time.
It just recycle views if it decided to kill them or if it's in need for memory. Or upon a configuration change.
A user expects an activity’s UI state to remain the same throughout a configuration change, such as rotation or switching into multi-window mode. However, by default the system destroys the activity when such a configuration change occurs, wiping away any UI state stored in the activity instance.
Overall I think you had the right approach.
And just use onStop() (and not onPause() because of some Dialogs and other intercations that removes focus from your Activity) to clear your views if you want to.
Take a look at the android activity lifecycle https://developer.android.com/guide/components/activities/activity-lifecycle
One way to make sure all your data is cleared is to override the onPause function and clear your data manually. onPause is called when your application moves to the background.
No, it does not remove data because, according to the lifecycle of Android, when you do background the views, onPause() and onResume() is called and your views and its instances are in onCreate() method.
So, by launching the views from background, it does not remove your data of views.
I am not understanding how android activities are managed.
I have an activity and every once in a while i have noticed that, when my app goes into the background, android destroys whatever the current activity is (say Activity3) and several other singletons and objects etc. Thats fine. The problem is when the app is resumed then intuition tells me that since android has destroyed the activity and objects for memory or whatever, then android would just restart the app completely from Activity1 so all the objects and data members would get properly initalized.
NOT SO!
It seems that when my app is resumed, the Activity3 is recreated and onCreate is called with the same parameters as it was the first time (when it was called from Activity2) only this time all the singletons and other objects that were initialized in Activity1 and Activity2 are recreated with their default values and are rendered useless.
How is this a safe policy/technique? How can android just randomly destroy objects and activities and then when the user resumes just call onCreate on the recent activity and expect everything to be hunky doory and NOT have to go through the proper startup procedure/initialization?
UPDATE / SOLUTION
Thanks to the commentors for their excellent info.
ACCORDING TO ANDROID DOCUMENTATION
onCreate
Bundle: If the activity is being re-initialized after previously being shut down then this Bundle contains the data it most recently supplied in onSaveInstanceState(Bundle). Note: Otherwise it is null.
THEREFORE what I ended up doing is I set TWO flags. One in onSaveInstanceState in the Bundle so to know that it is a valid Bundle set by me. The other in the class itself to determine if onCreate was called because of recreation or Auto-Rotation. And so in onCreate I checked to see if onSaveInstanceState is not null, check the Bundle flag, and check bInit (which defaults to false). If both flags are true then it means android dumped and destroyed our apps memory and the safest way to ensure everything is initialized again in a linear-style application is to just restart it and launch the beginning activity.
public class SomeMiddleActivity extends AppCompatActivity
{
private static boolean bInit = false; // only way it will be false again is if android cleared our memory and we are recreating
#Override
public void onSaveInstanceState(Bundle state)
{
// set a flag so that onCreate knows this is valid
state.putBoolean("StateSaved", true);
super.onSaveInstanceState(state);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
// this must be called first always for some reason
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
{
if (savedInstanceState.getBoolean("StateSaved", false) && !bInit)
{
// we were recreated... start app over
Intent intent = new Intent(getApplicationContext(), Startup.class);
startActivity(intent);
finish();
return;
}
}
bInit = true; // this will stay true until android has cleared our memory
.......
}
Although this has worked thus far, if anyone has a different suggestion let me know. I will be posting another article on this.
And FYI: the onSaveInstanceState(Bundle, PersistableBundle) version of onSaveInstanceState is never called ever so I dont know why they even implement it. (?)
#goldenb #Rishabh Thanks to goldenb and Rishabh for the insight.
Android, if destroys, also gives you tools to handle it.
Mobile devices have limited amount of memory which needs to be shared among Applications running simultaneously. Thus, smart resource allocation is necessary. The Apps running on foreground are used by End-User and gain high priority for better performance and user experience. Thus, applications running in background need to release the resources to suffice the memory requirements for foreground applications. Hence, background applications are destroyed (not completely) sometimes (in case of low memory).
Android Activities have Callbacks likes onSaveInstanceState() and onRestoreInstanceState() which enable you to save your current state of Activity (i.e., values of variables) when it is destroyed and retrieve them when the Activity is recreated.
You can get more information from here: How to save and retrieve the state of Activity using onSaveInstanceState and onRestoreInstanceState.
You can perform validations on the retreived state to ensure the Activity performs exactly as it was doing pre-destruction. You would find it very easy and logical once you get hands-on it.
Just giving my 50 cents on the issue. The correct way to deal with the issue of an activity being killed by the system for its resources in background is a common problem in android and according to Google the solution for this is:
onPause() is where you deal with the user leaving your activity. Most
importantly, any changes made by the user should at this point be
committed (usually to the ContentProvider holding the data).
Emphasis is mine. But what this means is that the Android lifecycles are designed so that under normal conditions onPause should be called as an Activity or Fragment is sent to the background. They hint at this in several of the android documentation pages:
As your activity enters the paused state, the system calls the onPause() method on your Activity, which allows you to stop ongoing actions that should not continue while paused (such as a video) or persist any information that should be permanently saved in case the user continues to leave your app.
Also worthy of your attention: if you wish that views are restored during Activity recreation, you should have set the ID attribute of all views ;)
Note: In order for the Android system to restore the state of the
views in your activity, each view must have a unique ID, supplied by
the android:id attribute.
PS.
You were wondering why onSaveInstanceState(Bundle, PersistableBundle) is not called, one possibility is that you do not have the right activity attribute set
This is the same as onRestoreInstanceState(Bundle) but is called for
activities created with the attribute persistableMode set to
persistAcrossReboots..
I have an Android existential question:
Does an App's onDestroy() get called when I kill it by swiping it out of the task manager?
If not... how can I detect a "killing" swiping event on the app, and do some final stuff beore it dies?
onDestroy()
Perform any final cleanup before an activity is destroyed. 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.
Note: do not count on this method being called as a place for saving data!
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.
Instead, rely on onPause() and onStop() to do any final work before your app goes out of view.
Is your main concern the "swiping" event or just saving data? :)
I am new to Android development and I am still not able to understand the onPause() and onStop() methods in an activity.
In my app, I have a static class that I name Counter, and it keeps the state of variables in memory for the app. My app runs fine in the emulator. What I was trying to test was differential behavior of onPause() versus onStop().
For onPause, I wanted the values stored in the Counter class's members retained, whereas calling onStop() I wanted the counter values reset to zero. So I override onStop() and set the variables inside the counter class to zero. However, in the emulator, I cannot seem to get the app in the Paused state. In the emulator, I open my app, exercise it. Then I hit the home button (not the back button) of the emulator, and launch another app, believing that this would mimic onPause() activity. However, the emulator does not appear to honor this (I am using an armeabi v7a emulator), it seems to always be calling onStop() because my counter values all go back to zero, per my override in onStop(). Is this inherent to the emulator or am I doing something wrong to get my activity into the paused state?
I'm not sure which emulator you are testing with, but onPause is the one method that is always guaranteed to be called when your Activity loses focus (and I say always because on some devices, specifically those running Android 3.2+, onStop is not always guaranteed to be called before the Activity is destroyed).
A nice way to understand the Activity lifecycle for beginners is to litter your overriden methods with Logs. For example:
public class SampleActivity extends Activity {
/**
* A string constant to use in calls to the "log" methods. Its
* value is often given by the name of the class, as this will
* allow you to easily determine where log methods are coming
* from when you analyze your logcat output.
*/
private static final String TAG = "SampleActivity";
/**
* Toggle this boolean constant's value to turn on/off logging
* within the class.
*/
private static final boolean VERBOSE = true;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (VERBOSE) Log.v(TAG, "+++ ON CREATE +++");
}
#Override
public void onStart() {
super.onStart();
if (VERBOSE) Log.v(TAG, "++ ON START ++");
}
#Override
public void onResume() {
super.onResume();
if (VERBOSE) Log.v(TAG, "+ ON RESUME +");
}
#Override
public void onPause() {
super.onPause();
if (VERBOSE) Log.v(TAG, "- ON PAUSE -");
}
#Override
public void onStop() {
super.onStop();
if (VERBOSE) Log.v(TAG, "-- ON STOP --");
}
#Override
public void onDestroy() {
super.onDestroy();
if (VERBOSE) Log.v(TAG, "- ON DESTROY -");
}
}
I know your question was 6 months ago but in case someone else stumbles on this question:
am I doing something wrong to get my activity into the paused state.
Yes, you are. This:
I hit the home button (not the back button) of the emulator, and
launch another app, believing that this would mimic onPause()
activity.
Hitting the home button will indeed call the onPause() method but because the home button makes your activity no longer visible it will then call the onStop() method (like patriot & milter mentioned).
As per the Activities developer reference (http://developer.android.com/guide/components/activities.html) you can display a dialog or simply put the device to sleep.
Alternatively, you call an activity that will only partially obstruct the calling activity.
So call an activity that creates a window with a view of size:
android:layout_width="100dp"
android:layout_height="100dp"
Which doesn't cover the entire screen, thus leaving the calling activity behind partially visible, thus calling only calling activity's onPause() method.
Clone that activity so that both view sizes are "match_parent" instead of "100dp" and call it and both the onPause() and onStop() methods of the calling activity will be called because the calling activity won't be visible.
There can be exceptions of course, like if the called activity causes an app crash in either of its onCreate(), onStart() or onResume() then the onStop() of the calling activity will not be called, obviously, I'm just talking about the general case here.
The differences between when onPause() and onStop() are called can be pretty subtle. However, as explained here, onPause() will usually get executed when another activity takes focus (maybe as a pop up, or transparent window) while the current activity is still running. If you navigate away from the app completely (for example, by hitting the home button), the activity is no longer visible and the system may execute onStop(). I only say may because, as Alex mentioned, there are some cases where onStop doesn't get called before the Activity is destroyed.
onPause():
"If an activity has lost focus but is still visible (that is, a new non-full-sized or transparent activity has focus on top of your activity), it is paused. A paused activity is completely alive (it maintains all state and member information and remains attached to the window manager), but can be killed by the system in extreme low memory situations."
onStop():
"If an activity is completely obscured by another activity, it is stopped. It still retains all state and member information, however, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere."
Taken from android reference activity class: http://developer.android.com/reference/android/app/Activity.html
If you are emulating Android 4.x you can control how the system handles background activities using Settings -> Developer Options -> Don't keep activities and Background process limit. For older versions there is an app called Dev Tools which contains the same settings. However, on low memory conditions the system can disregard those settings and terminate your application. Increasing the amount of memory assigned to the emulator might help.
Also, if you are re-launching your app from Eclipse, it will kill the previous process instead of gracefully terminating it.
I agree with milter!
onPause():
"If an activity has lost focus but is still visible (that is, a new non-full-sized or transparent activity has focus on top of your activity), it is paused. A paused activity is completely alive (it maintains all state and member information and remains attached to the window manager), but can be killed by the system in extreme low memory situations."
If you swap applications without pressing Back (press and hold HOME) then the OS is going to call onPause. When you return to your activity (press and hold HOME again) in onResume you should have all of your private variables preserved. But you can't control the user, right?!
if you anticipate that the user is going to leave your app and the OS calls your onStop you better save your data if you intend to resume where you left-off.
I have a Timer also, I need to save the elapsed time so when the user returns I can restore the data.
here is my example to save:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putLong("elapsedTime", elapsedTime);
// etc.
}
And my code to restore:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
elapsedTime = savedInstanceState.getLong("elapsedTime");
}
Place these methods inside of your class and you are good to go. Keep in mind that the string "elapsedTime" in my case is a KEY to the system and it must be unique. Use unique strings for each piece of data that you would like to save. For example "startClock", "ClockTextColor", etc...
Looking at the Activity Life Cycle diagram, I notice that onPause() and onStop() can both lead to the "process" being killed. This would require onCreate() to be called when the user wants to resume their application. The point being that onStop() is not necessarily called, nor is onDestroy(), but that onPause() may be the only event that the Activity may see. This being the case, onPause() must handle saving the application status so that the user can return back to it later, regardless of whether onStop() is called or not.
I can see onDestroy() being used to clean up Activity specific resources that would naturally be eliminated in a process kill action. Is there anything else that onDestroy() would be good for?
And what would onStop() be good for? Why would I want to override it for?
If I got your question right: It depends what you want to do with your application. Let's say you are programming application that uses GPS. In the onStop() which is called when the activity is no longer visible to the user, you can remove these requests. Or you can stop the some service if your application is running any. Or you can save preferences (not recommended, do it in onPause() instead), or you can close permanent connection to a server.....If I think of anything else, I'll add more...
If you have read the doc further, you'll see following:
Saving activity state
The introduction to Managing the Activity Lifecycle briefly mentions
that when an activity is paused or stopped, the state of the activity
is retained. This is true because the Activity object is still held in
memory when it is paused or stopped—all information about its members
and current state is still alive. Thus, any changes the user made
within the activity are retained in memory, so that when the activity
returns to the foreground (when it "resumes"), those changes are still
there.
However, when the system destroys an activity in order to recover
memory, the Activity object is destroyed, so the system cannot simply
resume it with its state intact. Instead, the system must recreate the
Activity object if the user navigates back to it. Yet, the user is
unaware that the system destroyed the activity and recreated it and,
thus, probably expects the activity to be exactly as it was. In this
situation, you can ensure that important information about the
activity state is preserved by implementing an additional callback
method that allows you to save information about the state of your
activity and then restore it when the the system recreates the
activity.
Summary: After completing onStop() Activity object is still alive in memory. And this will help the system to restore the activity.
Very basic example: consider you are showing your activity to user, and suddenly your friend calls you! Rest you can understand..
So now it it up to you that, which are the resources/objects/connections should be released on which event.
Another example would be to register and unregister a broadcast receiver.
Note that usually these things are placed in onResume and onPause, the difference is subtle though, onResume/onPause are called when the activity gets placed behind another activity, onStart/onStop are called when the activity is no longer visible in the screen.