The Android documentation regarding the recreation of an activity states:
When your activity is destroyed because the user presses Back or the activity finishes itself, the system's concept of that Activity instance is gone forever because the behavior indicates the activity is no longer needed. However, if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed.
To clarify: does this mean that onSavedInstanceState becomes null when the user presses the back button?
Thanks
Unfortunately, it seems yes... Android follows many bad design decisions :(
Related
What is the exact life-cycle path for an Android activity when it is shown to the user in the recents screen and when it renters into the user's view? I want to know if I can determine if the user left the app (onPause() and/or onStop()) is called and then returned back to it with the activity remaining in the foreground.
It depends. Is the activity still resident in memory or was it destroyed? In the first case, it would get onStart, then onResume. In the second, it would go through the entire normal lifecycle of any activity being launched (including onRestoreInstanceState to restore any saved values).
Recents screen does not show your activity, it shows only its screenshot. When your app re-enters into the user view (when you sekect from recents), it depends. In most cases, app is not killed, so sequence is onRestart ->onStart->onResume. If app is killed or phone restarted, onCreate->onStart->onResume
Look here:
https://developer.android.com/guide/components/activities/activity-lifecycle
I was looking at this page from "Android Programming" by big nerd ranch, and I was confused by the sentence beneath. It states that "when the activity is stashed, an activity object does not exist." This is confusing to me because when I open an app and press the home button, onPause() is called and the activity reaches a "Paused" state with its activity stashed in the OS, as shown in the figure. It must be still running in the background because onDestroy() is not called when I press the home button. In fact, when I open my task manager, I can see how the activity looked like when I pressed the Home button. What exactly do they mean by "activity object does not exist?" when it is clearly on paused state in the background?
THeir documentation looks to be a bit wrong and confusing. The official Android documentation doesn't talk about a "stashed" state, it would be the block "App process killed" in the documentation here
Basically, from the STOPPED state only, the OS may destroy your activity at any time. If it does this, is will call onSaveInstanceState. The Activity variable would then be invalid. At any time, it may then recreate a new Activity and call onCreate then onRestoreInstanceState on it, passing in the Bundle you save previously, to recreate the activity.
This is confusing to me because when I open an app and press the home
button, onPause() is called and the activity reaches a "Paused" state
with its activity stashed in the OS, as shown in the figure.
I would not say that this is "stashed". Your activity is alive and well, just paused.
It must be still running in the background because onDestroy() is not
called when I press the home button.
That's right. When you are hitting the home button you are saying to the OS "Hey I'm going somewhere else, but I'm not necessarily done with this activity."
If you instead hit the back button, then you'll see onDestroy called. Here you are saying to the OS "Ok I'm done with this activity, do with it what you want."
What exactly do they mean by "activity object does not exist?" when it
is clearly on paused state in the background?
The stashed state is entered when the OS needs to destroy your activity without you "telling" it to do so (i.e. hitting back button). This happens when your device goes through a device configuration change. A classic example is rotation. This also happens if the OS needs to free up memory. In this case onSaveInstanceState will be called to capture the state of your activity in a Bundle. The stashed state is then the preservation of this Bundle and the class name of your activity. The actual Activity object is marked for garbage collection. Then given just the Bundle object and the class name of your activity, the OS can create a new instance of your activity if the user returns to it.
One take away is that you don't have to implement onSaveInstanceState yourself unless there is specific information you want preserved. Some components of the view hierarchy will automatically add information about themselves to the Bundle because the super Activity.onSaveInstanceState will still be called. From the docs:
The default implementation takes care of most of the UI per-instance
state for you by calling onSaveInstanceState() on each view in the
hierarchy that has an id, and by saving the id of the currently
focused view (all of which is restored by the default implementation
of onRestoreInstanceState(Bundle)). If you override this method to
save additional information not captured by each individual view, you
will likely want to call through to the default implementation,
otherwise be prepared to save all of the state of each view yourself.
http://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)
You can check the source here:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/Activity.java#1371
In Andoid Acitivity life cycle, why does an activity go through onPause() before going to onStopped()? Why can't the state go directly to onStopped()?
Paused and stopped are related but different states. From the point of view of the user, a paused activity cannot be interacted with, but may still be visible (e.g. if it has called a different Activity as a dialog). A stopped activity is guaranteed to be not visible at all (the uses is in another Activity or even a different app).
Of course, stopped implies paused, but the reverse is not the case.
From the official documentation.
If an activity in the foreground of the screen (at the top of the stack), it is active or running.
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 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.
An even more detailed explanation is given in the Managing the Activity Lifecycle article in the Training section of the Android Developers site.
Refer to the documentation on Activities:
http://developer.android.com/reference/android/app/Activity.html
onPause()
"Called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity will not be resumed until this method returns.
Followed by either onResume() if the activity returns back to the front, or onStop() if it becomes invisible to the user."
Note: I would say "resuming another activity" instead of "resuming a previeous activity".
onStop()
"Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed.
Followed by either onRestart() if this activity is coming back to interact with the user, or onDestroy() if this activity is going away."
Because the documentation says so :-)
And it makes sense. The app is open and the user pressed the home button: onPause() gets called. After a while the system needs the memory and closes the app: onStop() gets called.
Because, onPaused() is executed when your App is rotated or a Dialog is open.
onStop() when your App is not in the screen, so is necesary that this two points in the lifecycle to the user or programmer can identify what action is executed.
I have an app in which I programmatically create an EditText view. I assign an ID to that view using setId()
myEditText.setId(100);
so that Android automatically saves that object's state when pausing/stopping the app (as I was advised to do here). It works in these cases:
(1) When I leave the app using the "Home" button: if I then come back to the app, the object's state (displayed text) is restored, as expected.
(2) On a screen orientation change (which involves Android automatically destroying the activity and restoring it through a Bundle). The object state is also kept.
However, it doesn't work in this case:
(3) When I leave the app using the "Back" button: if I then come back to the app, the EditText object is empty.
Any explanation as to why this happens? Does Android really distinguish between leaving the app with "Home" and with "Back"? According to the documentation, the object's state should be automatically preserved, through a Bundle, even when the activity is destroyed. And that clearly happens in case (2). But not in case (3)!
If this is normal behaviour, how could I have the app's state automatically saved and restored when the user presses "Back"? I know I could use the SharedPreferences for that, but I'd rather have Android do that automatically, just as it does in cases (1) and (2).
This happens at least in Android 4.0 and 4.2 (I haven't tested others).
You really should study activity life cycles as there are many many ways to solve the problem. Since your activity is typically pulled off of the stack and destroyed when you navigate back one quick but not necessarily the best way is to make sure your activity flagged as singleTop or singleInstance in the manifest that way it is not pulled off of the stack and recreated when you navigate back and forth. You could also use the singleton Application class. Or pass the text back and forth as params. Or use a database. Or use MVC or some other programming paradigm that will allow your views to be destroyed and recreated with out the data populating them going with it. Lots of "or's". Study activity life cycles and then look at how you have your application architecture setup already and choose the method that will work best for you.
http://developer.android.com/training/basics/activity-lifecycle/index.html
http://developer.android.com/guide/components/tasks-and-back-stack.html
I think I found the explanation. I only needed to read the doc more carefully (thanks to #lentz for one of the links); see here and here:
When your activity is destroyed because the user presses Back or the activity finishes itself, the system's concept of that Activity instance is gone forever because the behavior indicates the activity is no longer needed.
If the user presses the Back button, the current activity is popped from the stack and destroyed. The previous activity in the stack is resumed. When an activity is destroyed, the system does not retain the activity's state.
The above explains behaviour (3) in my question.
However, if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed. The saved data that the system uses to restore the previous state is called the "instance state" and is a collection of key-value pairs stored in a Bundle object.
The above probably explains behaviour (1) and (2).
What I don't see is why the user pressing Back should be interpreted as "the activity is no longer needed" ("its state needs not be preserved"). But that's a different matter.
I have an application that navigates to the same activity but each time the activity loads with different parameters. In my application it's a parsed data content retrieved from url. First thing I want to ask: When I push the backbutton of my device I get my earlier activity without being recreated. Is the objects in this activities alive and can I reference them?
Second question is if my first question doesn't make sense, what do you advice me to do?
If you look at the Activity life cycle, you'll notice that as long as your phone has enough memory, your first activity is kept in memory, and with it any member with the data it contains.
But if your phone needs to have some memory, it can kill any activity kept in background (any activity but the one being shown to the user), which means that you'll loose any data that was in your first activity.
To know which happened, keep in mind that the onResume() method will always be called when your activity is brought to foreground (either on creation, or when you navigate back to it), but onCreate() will be called only when your application is created from scratch (meaning you don't have any saved data).
You should use the bundle mechanism to save data when your activity is paused, and load it when you come back to it. Read the paragraph about Saving Activity state in Android doc to see how to use this.
You are not guaranteed that in memory data will be around once you leave an Activity. Read through this part of the dev guide thoroughly to understand the lifecycle of an Activity: http://developer.android.com/guide/topics/fundamentals/activities.html
If you need to persist information, you should override the onPause, onStop, and/or onDestroy methods of your Activity. You can then save your state using SharedPreferences, the SQLite database, or even a flat file.
In the manifest file add the following to the activity:
android:launchMode="singleTop"
In your example what is happening is when you navigate back to the activity using the back button you are bringing up the activity from the stack. When you navigate to the activity inside of the app what is happening is a NEW activity is being created, while the original is still on the stack. The singleTop launch mode will pop the activity out of the stack if it is there when you navigate to it in the app, and only create a new activity if it is not on the stack.
Without singleTop each time you launch the activity in the app it will create a new instance and you will find there are times you have to hit the back button on the same activity more than once due to multiple instances.