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...
Related
While we are having onStart method, what is the purpose of onRestart method?
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onRestart() {
super.onRestart();
}
Here is the activity lifecycle there is your onStart() and onRestart() methods with explanations
more info here
One case of onRestart() being called is when user presses home button and comes to launcher screen. In this case, activity is not destroyed and pause/stop events are fired. When user opens your app again, onRestart() for that activity is called before onStart(). You can find example here.
The onRestart() method will be called whenever the Activity comes back from the invisible state. Suppose, we pressed the home button of the device and coming back, this onRestart() will be invoked. For more info about this, please go through the documentation
You can read all about the Activity's lifecycle on Android developers: http://developer.android.com/reference/android/app/Activity.html#onRestart()
Taken directly from there:
Called after onStop() when the current activity is being re-displayed
to the user (the user has navigated back to it). It will be followed
by onStart() and then onResume().
For activities that are using raw Cursor objects (instead of creating
them through managedQuery(android.net.Uri, String[], String, String[],
String), this is usually the place where the cursor should be
requeried (because you had deactivated it in onStop().
Derived classes must call through to the super class's implementation
of this method. If they do not, an exception will be thrown.
Only 100% sure that onRestart is called is when you navigate away and then navigate back to the activity.
On the other hand, when you press home button and the app moved to background, there is no way we can know whether the app is destroyed by OS to claim back resources or it is still reside on memory. If the app is destroyed then onCreate will be called. Otherwise if the app is still available in memory then onRestart will be called.
According to this
Note: Because the system retains your Activity instance in system memory when it is stopped, it's possible that you don't need to implement the onStop() and onRestart() (or even onStart() methods at all. For most activities that are relatively simple, the activity will stop and restart just fine and you might only need to use onPause() to pause ongoing actions and disconnect from system resources.
Called after onStop() when the current activity is being re-displayed to the user (the user has navigated back to it). It will be followed by onStart() and then onResume().
For activities that are using raw Cursor objects (instead of creating them through managedQuery(android.net.Uri, String[], String, String[], String), this is usually the place where the cursor should be requeried (because you had deactivated it in onStop().
onRestart() is called after onStop() when the current activity is being re-displayed to the user.
e.g. The user has navigated back to it.
Adding to NightFury's answer. The onRestart() method is a callback method in the Android Activity lifecycle that is called when the activity is restarting after having been stopped.
Some use cases:
If an activity is paused or stopped and the user returns to it, the onRestart() method can be used to resume the activity from its paused or stopped state.
In some cases, the onRestart() method can be used to refresh the data displayed in the activity. For example, if the activity displays a list of items that are fetched from a server, the onRestart() method can be used to refresh the list after the user returns to the activity.
When the configuration of the device changes (such as screen rotation), the onRestart() method is called. This can be used to update the activity's layout or other resources to accommodate the new configuration.
Error handling: If an activity has encountered an error and was stopped, the onRestart() method can be used to reset the activity and handle the error.
I have a list activity which does the usual list activity type stuff. All of the activity setup was being done in the onCreate() method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_streams);
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
mActionBar = getActionBar();
mStreamListAdapter = new StreamListRowAdapter(this, R.layout.stream_list_row);
mStreamListView = (ListView)findViewById(android.R.id.list);
mStreamListView.setAdapter(mStreamListAdapter);
}
I do not have onStart() and onResume() overrides. I can successfully navigate out of this activity based on the menu buttons pressed and then navigate back to this activity. When I navigate away from this list activity via startActivity(newIntent), I do not call finish, but I do call finish in the newIntent activity, when coming back to this list activity. Everything works fine, unless either the ListActivity itself or one of the new Activities have been sitting in the background for a long time (i.e. I switched to another app). Long time is measured in hours. Sometimes (NOT always), when I come back to my app after this delay, the list activity does not display the list, the menu is not displayed either, just a blank screen with the activity title displayed in the ActionBar.
I realize that I need to handle coming back to the list Activity via onResume() (and maybe onStart()). But onResume() is always called after I navigate back to this list activity, how do I really know if the variables representing the ListAdapter and ListView have actually been destroyed by the OS and need to be recreated inside onResume(), I don't want to recreate them every time onResume() is called. Can I just check to see if they are equal to null? It's hard to test this, as this does not happen very regularly.
Thank You,
Gary
It sounds like you are missing some basic information about Android and Activity's lifecycle. First I want to mention how Android saves it's state. There are 2 important points here. When leaving an Activity it is at risk of being destroyed it calls the hook method
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("myKey1", 1);
outState.putString("myStringKey", "hello");
}
When this is called, this is a chance for you to save all the data that you'd like to persist. This could be ids, strings, arraylists, and nearly any other type of data.
Now that you've saved your data, in the onCreate method of your Activity you are passed back all of these values.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
String myStr = savedInstanceState.getString("myStringKey");
int myInt = savedInstanceState.getInt("myKey1", -1);
}
// do the rest of your setup
}
On the first time onCreate is called savedInstanceState is null. To answer your question: "how do I really know if the variables representing the ListAdapter and ListView have actually been destroyed by the OS" this is how you can know. If savedInstanceState is not null, your stuff has probably been destroyed. However, I will say that anytime onCreate gets called that Activity was already completely destroyed anyway.
The other thing I will mention is Android is allowed to kill your backgrounded Activity whenever it needs to reclaim some memory. When it does this, it will call the onSaveInstanceState method for you. Android does not have to restart the application at the "first" or "MAIN" screen of your application. It can start off several Activities in if that's where the user left off. I mention this because it sounds like you're having issues whenever Android decides to create your activities after it clear's it's memory. The best way to make sure your application works well when this happens is to just rotate the phone. Rotate the phone from horizontal to landscape and/or back will cause the Activity to be destroyed and recreated with onSaveInstanceState called and passed back in to the onCreate. Based upon the information you've provided this is the best I can suggest for now.
Cheers.
I have finally figured out what was going on. I have 2 activities, ActivityA and ActivityB, and an Application object. Upon the application launch, ActivityA initializes some globals that are stored in the Application object and then starts ActivityB. When my app is restarted after being in the background for a long time, the onCreate() of the Application is called and then onCreate() of ActivityB is called. ActivityB relies on the variables in the Application object that normally are initialized by the ActivityA, but ActivityA is never called this time around and the globals are not initialized. I am still not clear why the ActivityA just hangs, instead of crashing with some message stating that the variables are null, which is what onCreate() in the Application object sets them to, but regardless, when this occurs, I need to go back to ActivityA() and reinitialize everything as I normally would, when the application is launched.
I now have a boolean in the Application object that indicates whether or not ActivityA has been executed after the onCreate() of the Application object has been called. ActivityB checks this boolean flag, and if not set, then simply start ActivityA to perform the on launch type initialization. I actually have to do this check in pretty much every activity.
This question already has answers here:
onSaveInstanceState () and onRestoreInstanceState ()
(13 answers)
Closed 9 years ago.
I have a question regarding Activity Lifecycle in Android.
I want to know, in what situation the method onRestoreInstanceState() is called ?
The documentation says
"The system calls onRestoreInstanceState() only if there is a saved
state to restore"
But I want to know when can this situation occur. Is it only applicable in case of screen rotation, when the foreground activity is destroyed and recreated ?
From the link here:
onRestoreInstanceState() is called only when recreating activity after it was killed by the OS. Such situation happen when:
orientation of the device changes (your activity is destroyed and recreated)
there is another activity in front of yours and at some point the OS kills your activity in order to free memory (for example). Next time when you start your activity onRestoreInstanceState() will be called.
In contrast: if you are in your activity and you hit Back button on the device, your activity is finish()ed (i.e. think of it as exiting desktop application) and next time you start your app it is started "fresh", i.e. without saved state because you intentionally exited it when you hit Back.
Other source of confusion is that when an app loses focus to another app onSaveInstanceState() is called but when you navigate back to your app onRestoreInstanceState() may not be called. This is the case described in the original question, i.e. if your activity was NOT killed during the period when other activity was in front onRestoreInstanceState() will NOT be called because your activity is pretty much "alive".
All in all, as stated in the documentation for onRestoreInstanceState():
Most implementations will simply use onCreate(Bundle) to restore their
state, but it is sometimes convenient to do it here after all of the
initialization has been done or to allow subclasses to decide whether
to use your default implementation. The default implementation of this
method performs a restore of any view state that had previously been
frozen by onSaveInstanceState(Bundle).
As I read it: There is no reason to override onRestoreInstanceState() unless you are subclassing Activity and it is expected that someone will subclass your subclass.
Not only that, but also:
Usually you restore your state in onCreate(). It is possible to restore it in onRestoreInstanceState() as well, but not very common. (onRestoreInstanceState() is called after onStart(), whereas onCreate() is called before onStart().
Use the put methods to store values in onSaveInstanceState():
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
icicle.putLong("param", value);
}
And restore the values in onCreate():
public void onCreate(Bundle icicle) {
if (icicle != null){
value = icicle.getLong("param");
}
}
You do not have to store view states, as they are stored automatically.
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()
I have an issue. For analytic purposes I need to track when the APP (not activity) is resumed. The problem I have now is that if I put the tracker on the OnResume event of an activity, it will get fired every time the user goes back and forth on different activities.
How can I avoid that? How can I track the real "Application Resume," (when user actually exits the app and come back) and not the activity resume?
Any ideas is greatly appreciated. Thanks.
I encountered the same problem and solved it by creating base activity :
public class mActivity extends Activity{
public static final String TAG = "mActivity";
public static int activities_num = 0;
#Override
protected void onStop() {
super.onStop();
activities_num--;
if(activities_num == 0){
Log.e(TAG,"user not longer in the application");
}
}
#Override
protected void onStart() {
super.onStart();
activities_num++;
}
}
all the other activities in my app inherited mActivity. When an activity is no longer visible than onStop is called. when activities_num == 0 than all activities are not visible (meaning the the user close the app or it passed to the background). When the user start the application (or restarting it from the background) onStart will be called (onStart is called when the activity is visible) and activities_num > 0. hopes it helps...
Use the Application object of your app (see http://developer.android.com/reference/android/app/Application.html). If you create a custom Application class and configure it in your AndroidManifest.xml file you can do something like this:
Start tracking in the onCreate() of the Application object.
Instrument all your Activities so their onPause() and onResume() methods check with the Application object and see if they are the first Activity to run, or if they are continuing a previously running instance of the app.
Stop tracking in the onDestroy() of the Application object.
To a certain degree most of the analytics packages (Flurry and their ilk) do something similar to this. You'll need to do a little state machine work to get this to work right, but it shouldn't be too complicated.
Instead of OnResume(), hook into the OnCreate() event of your main activity.