I have a problem with my application when it is brought back to the foreground in the case the phone went low on memory while the application was hidden:
The class inheriting from Application is re-created (onCreate is called again), thus losing data it held before. The Activity which is restarted is not the one tagged as main action in the Manifest, but the last one that was active. This is a problem as the main activity, from which the user logs in, is the one responsible for filling in the Application subclass' data and I can't fill it in later.
Is there any way to tell the application to restart at the main activity instead of the latest one in this case ?
You could check in onResume() if the user is logged in. Means that you check if your Application data is filled. If this is not the case, finish the activity and start your first Application.
The user expect to return to the latest activity, so a general "always start first activity" would upset the user...
you could keep the data by implementing methods such as onPause() and onResume()
Check this link out: http://developer.android.com/reference/android/app/Activity.html
this answer might also be helpful: onSaveInstanceState () and onRestoreInstanceState ()
Related
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
I have a flow in my android app where it is possible to open a chain of user profile activities, one activity from another.
Example : User profile A is opened where it contains a list of other user profiles. clicking an item from this list will open user profile B. Again, it lists other user profiles where user profile A might be part of. So clicking this item will open another activity of user profile A.
The app user can perform an action on the current activity of user profile A which needs to be reflected on all other user profile A activities in the back stack. So what i did was registered a receiver in the user profile activity that checks for the activity user id against the one coming from the broadcast and perform the relevant actions on the UI.
The problem is, that i cannot unreigster the receiver on onPause() or onStop() (according to a lot of threads recommendations here) since this is kindda counterproductive to what im trying to build here. And according to the documentation onDestroy() is not guarunteed to be called every time the activity terminates.
So what im basically asking here is - Is it a good practice to register all activity receivers on onCreate() and unregister them both on onDestroy() and onSaveInstanceState() so i will be 100% sure they are cleaned up on activity destruction ?
The only mention i saw in the documentation that recomments not to unregister receivers in onSaveInstanceState() was here - BroadcastReceiver - and it only says
Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack
EDIT:
Ok, i just saw this quote in the onDestroy() spec :
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.
So onSaveInstanceState() will not be called also.
But arent receivers qualified as things that are NOT "intended to remain around after the process goes away" ? I dont get why onDestroy() is not called in such situations. What happens to other resources that are released there (not just receivers) ?
In your case, using broadcast receiver to detect which Activity instance is running is not a good idea. You should use single instance for every Activity. Another solution is that you can create view stack in one Activity instead of Activity stack. Switching view is easier than switching Activity. As to how to use onDestroy and onSaveInstanceState(), it depends on your scenario. If you finish your Activity, the onDestroy will be called. If your Activity is destroyed by system in some situation, like screen rotation, the onSaveInstanceState will be triggered.
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.
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.
I have two activities. One loads all rows from a database, and the other saves to the database. When I have the second save in onStop and the first repull the data in onResume, they do it out of order (the first resumes and then the second saves). I managed to fix this by putting the saving data in onPause, but why was this happening? Was this the cleanest way to do it?
Doing the save in the first actvity's onPause should be fine.
You've discovered that the foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). During this time, the activity is in front of all other activities on screen and is interacting with the user.
When you start the second activity, onPause is called on the first and then interactive control switches to the second, with onStop on the first to be called somewhat in background.
This improves responsiveness and gets the new activity in front of the user ASAP. Consequently, you should try to keep your onPause implementation as fast and efficient as possible.
See the following Android docs for more details on the lifecycle http://developer.android.com/guide/topics/fundamentals.html, but what you have found should work fine for you.
Some official quote as an add-on:
The Activity documentation states that
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