I have an activity in which I collect data for an online transaction. When the collection is done, I run a background thread (more specifically an AsyncTask) that calls a web-service and waits for its response, then return it to the activity. Meanwhile, a progress dialog shows up.
I want the background process to be cancelled if the application finishes or user cancels (however, I still need to notify the web-service), and retained if the activity is destroyed due to a configuration change or to free memory. I understand that I shall use onRetainNonConfigurationInstance() to detach my activity from the AsyncTask, retain it, and then reattach in the next activity, I already have the infrastructure for that. I also know that in some lifecycle callback, the isFinishing method tells me if my app is shutting down normally; and I do believe I can also handle the user cancel in the progress dialog's callback.
I have two simple questions:
Will onRetainNonConfigurationInstance() be called if my activity is
killed due to low memory? (I know it will be if the reason is a
configuration change.)
What is the situation (as emphasized by the developer guide) in which onStop() and onDestroy() are not called? (I want to know if my
code handling the cancellation would always execute.)
All in all, can I be sure that by implementing onRetainNonConfigurationInstance() and onDestroy() with isFinishing() checked, in every situation, my background thread will be handled accordingly?
BONUS question: If my application is killed for some reason (let's say permanently), how can I provide a way for the AsyncTask to save the response anyway? Can I retain an instance of shared preferences in it and write the data in that?
Will onRetainNonConfigurationInstance() be called if my activity is killed due to low memory?
No. Your activity is never individually killed for low memory. Your whole process may be terminated due to low memory, but onRetainNonConfigurationInstance() is only designed for in-process use.
What is the situation (as emphasized by the developer guide) in which onStop() and onDestroy() are not called?
Your process could be terminated due to low memory conditions (onStop() is very likely to still be called, but onDestroy() might not be if Android is in a hurry, such as due to an incoming phone call). Also, your app could crash with an unhandled exception. I am not certain if onDestroy() is called if the user force-stops you, but I doubt it.
All in all, can I be sure that by implementing onRetainNonConfigurationInstance() and onDestroy() with isFinishing() checked, in every situation, my background thread will be handled accordingly?
"Every" is a strong word. If Android terminates your process, your thread is gone as well.
If my application is killed for some reason (let's say permanently), how can I provide a way for the AsyncTask to save the response anyway?
Write the data to disk before doing anything else, and hope you are not killed before that point. Then, next time you run, notice that this saved data is floating around and arrange to do the rest of your work on it.
Related
If I, for example, need to keep some very important data which the user can edit within my app, should I need to save them every time user changes such data or is it ok if I would save it within onPause(), onStop() or onDestroy() methods?
Can somehow application end without any of those methods calling? (For instance when battery runs out)
This certainly can't be done in onDestroy().
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, so
it should not be used to do things that are intended to remain around
after the process goes away.
So yes, the application can end without calling any of the lifecycle methods.
In that scenario when the phone is shutting down, you can use the ACTION_SHUTDOWN Intent.
More info here. For all other cases onPause should do the work. Even in the link provided, there is a statement that onPause will be called if the app is in FG.
Apps will not normally need to handle this, since the foreground
activity will be paused as well.
However, if it is not so expensive operation, I would go with saving data after edit.
As per the documentation of Android activity life cycle, onPause is called when an activity is going into the background, but has not (yet) been killed.
Hence, in most Android documentation, and sample codes you will find onPause is used for saving any persistent state the activity is editing, to present a "edit in place" model to the user and making sure nothing is lost if there are not enough resources.
So in your use case, all you need to do is implement onPause for your Activity and write a code to Save the activity state (EditText content or any other ongoing user interactions). Android system will save the activity state which you can always get back in onCreate of your Activity when android launch your activity next time.
in this case please verify your phone activity via debug interface , some of phones are terminate your application this is force quit.
Going of this question
android save game state in onPause or onDestroy?
The answer highlighted that the person asking the question should save game state in onPause because the onDestroy documentation says "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." In these situations, how can we ensure onPause will be called? Is it possible to control what methods are called in these situations? Seems unpredictable
onPause will be called every time your activity leaves the screen, before it is finished or if something overlays your activity that keeps the user from interacting with your activity.
You don't need to worry that onPause is not called.
For more information look into the starting and stopping activity training or the Lifecycle Api Docs
You should save temporary instance state in onSaveInstanceState(). This method recieves a Bundle parameter which you can use to write state to. The Bundle is then sent to onCreate() when your app is restarted.
If you need to save instance state more permanently, then save it to a database or SharedPreferences. According to http://developer.android.com/training/basics/activity-lifecycle/stopping.html, you should use onStop() for more CPU-intensive operations rather than onPause(). I don't think you need to worry about onPause() being called in normal use cases. As far as I can tell, it is guaranteed. (Of course, there are always catastrophic failures, such as the user pulling out the battery of the device, but there's not much you can do about that.)
It's almost certain that onPause() will always be called. The reasoning is that it's highly unlikely the "system" will aggressively kill an active (i.e., visible) Activity.
In order to free resources, the Android OS effectively reserves the right to kill dormant processes - in particular ones that have been long-running but not recently used. In order for your Activity (and its process) to qualify for this, at some point you must have sent the Activity to a background state, e.g., pressed HOME or started another app's Activity. The simple fact your Activity is no longer visible means it will have been paused and onPause() will have been called. It's almost certain that the Activity will have been stopped and onStop() will have also been called.
What you have to remember is Android has been around for a while now and early devices had RAM measured in 100s of MB and the system behaviour possibilities and documentation reflects this. More recent devices have RAM measured in GB (even 10s of GB) so unless a user really pushes their device to the limitations of its resources, aggressive clean-up of app processes becomes less likely.
You can show Dialog for User to Act Accordingly.When Dialog will be opened to ask user that he wants to quit or not,Activity will definitely call onPause() and at this time you can write your game state saving code. Its better to write code on onPause() because at onDestroy() resources are freed by os.
More concretely: Is it safe to place the canceling of a task in onDestroy? Also, is it safe to use onDestroy for unregistering receivers and freeing up resources?
My aim is to make sure that my task is canceled/destroyed when the Activity is destroyed, but not before.
onDestroy():
is called when the activity is destroyed and resources must be
released.
is NOT called when the activity is destroyed in a hurry (when the
system is low on resources etc).
The first case is clear: I do all cleaning in onDestroy and no problems arise. The second case is a bit of a problem though. When the Activity is destroyed and onDestroy is skipped (so I don't cancel my task), could it happen that the task continues execution, then completes and tries to update the dead Activity, so the app crashes?
We come to the real question:
When an Activity is killed and onDestroy is skipped, is everything attached to that Activity automatically destroyed? (Is onDestroy skipped only in case that everything will be wiped out altogether? Tasks, registered receivers etc)
If onDestroy is skipped does this mean that the whole app is being killed?
Let's focus on onDestroy(), because the solution is not in onPause() or onStop(). Arguments:
onStop() could be skipped when the Activity is being destroyed, just like onDestroy
onPause is called too early and too often, so it is not appropriate for the use case. Examples:
Screen lock: onPause can be called when the device screen is locked. Very often this happens like a screensaver and the user unlocks immediately because he is standing there looking at the screen. Canceling tasks and stopping everything my app is doing in such a case will only degrade user experience. I don't want my app to choke and misbehave just because of an incidental "screensaver".
In an example app I have two screens that are Activities. The user can quickly switch between them. In this app users tend to switch screens often and quickly.
Navigation: One of the screens has a map which receives location updates from the system. It records a precise graphical log of the changes in location (route), so it needs to run constantly until the Activity is closed. Normally I would register and unregister any receivers in onResume and onPause. However, this would make the app very unusable, as the updates on the map will stop every time the user navigates away. Therefore, I would like to unregister the receivers in onDestroy.
Loading list: The second screen has a list that shows data from a webservice. It takes 4 seconds to download the data. I use an AsyncTask and I know I should cancel when necessary. It should not be canceled in onPause, because it should continue loading while the user switches between screens. Therefore, I would like to cancel it in onDestroy.
There can be many more examples. Some of them might not be totally appropriate in everyone's opinion (you might even suggest using a service instead of AsyncTask). But the idea is important, and all of them have the same idea: keep on doing work that's specific to the Activity, while the Activity is paused, but ENSURE to stop doing it when the Activity is destroyed. (It does not matter whether I am using an AsyncTask or a Service. In either case, the work should be stopped when the Activity is destroyed.)
P.S. If the answer is that it is not safe to do the clean up in onDestroy, this would mean that the Android framework requires us to stop everything we are doing in onPause. And then I would not see any reason for using onDestroy...
I would like to refer you to this baby: http://developer.android.com/reference/android/content/ComponentCallbacks2.html#onTrimMemory(int)
Essentially it gives you all the places where the system finds it useful to cancel tasks and clean its memory:
Please take a closer looks at the following 2 cases:
TRIM_MEMORY_UI_HIDDEN - the process had been showing a user interface, and is no longer doing so.
TRIM_MEMORY_COMPLETE - the process is nearing the end of the background LRU list.
Which are the cases for most of what you asked.
In the same method you can also catch TRIM_MEMORY_RUNNING_CRITICAL which will alert you to a case where the system has no memory and special actions must be taken immediately.
This method has made my development life much better in similar cases.
If you just need to do some cleanup, no matter how the activity is closed, you should be able to use a combination of onSaveInstanceState() and onDestroy(). One of those should be called no matter what. Maybe have a boolean cleanupDone in your activity, which is set whenever one of the two finishes.
Concerning saving of user data, have a look at Saving Persistent State:
Google suggest a
"edit in place" user model
That is: save as soon as the user creates new data, at the latest in onPause(). This does not mean that you need to recreate the data in onResume(), just that it should have been saved.
By the way: onStop() can be skipped only on pre-Honeycomb devices, that is, as of June 2015, less than 6 % of all devices. Still, onSaveInstanceState() should be called if either onDestroy() or onStop() are omitted.
As far as I gone with android,
1 When your apps crashes every resource relevant to it are destroyed.
2 When the device changes configuration resulting the Activity to be destroyed and recreated.
3 When apps running in background and Android kill it due to running on Low Memory
apart from these the other callback method are called i e
1 when another Activity come in front , or your device locks ..etc
In all case according to your requirement you can release all your resources in onDestroy and cancel the Thread and Asyntask and stop all the services etc .if you want your task remain paused and alive while on destroy called then you can save the configuration and retain it while onCreate is called again by check is null or not.
I am trying to implement a 'resume' feature for a game I'm developing. It should work as follows:
If the user starts a game and later closes the game with finishing, the game state is saved. When opening the app again, a 'resume' option will be available.
If the activity is only paused (e.g. minimized due to a phone call) and the user returns, it should show the game in progress. It should not terminate and save the state, unless of course, the OS decides to kill the activity.
I've decided to use SharedPreferences for the most part, as well as a custom file to save extra information. I've seen a lot of people recommend saving the state of the program in the onPause() method and I've been wondering why this is the case.
From what I can gather, using OnDestroy() would be better. onPause() does not mean the activity will be killed so I could be wasting time when saving the game state necessarily. I've checked my program and onDestroy() is being called at the appropriate times. I'm assuming therefore I have no leak keeping the activity from being destroyed.
Despite this, I cannot find anywhere recommending to save state in onDestroy() and everyone seems to recommend using onPause. Am I missing a piece of information here?
Despite this, I cannot find anywhere recommending to save state in onDestroy() and everyone seems to recommend using onPause. Am I missing a piece of information here?
You are :). onDestroy() is not guaranteed to be called. See the documentation for it:
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here. This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. 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.
I know my question caption must have sounded really vague. But let me clear it out here.
Say I have an android application over a middleware stack. In onCreate() of my activity, I initialise my middleware modules.
In its onDestroy(), I must de-initialise the middleware. Now my middleware calls may take quite some time to process. So I want to know how much time the onDestroy() function has, and see whether my deinitialisation can take place within that time.
Is it reasonable to keep my de-init in the onDestroy()?
Also, suppose I initialise the middleware in onCreate() of activity A1. On a button click, activity A1 switches to activity A2. In low memory situations, the LMK will kill the activity that has not been in use for some time. In such a case, won't activity A1 be killed? When activity A1 is killed, will all instances I create in A1 also get destoryed?
Regards,
kiki
I believe you are rather confused to ask this question.
In order to get a good comprehension of what is happening, you should take a look at the lifecycle graphs that can be found on developer.android.com:
Activity lifecycle
Background service lifecycle
You will see that Activity.onDestroy() only gets called in the case of a controlled shutdown of the activity - something that happens extremely rarely, as the Android OS can kill your process in a variety of states without ever calling your onDestroy() method.
What and why do you need to de-initialize?
If you're worried about releasing resources, then most of them will get released anyway when/if your process is killed.
If you are worried about saving the user's data (your application's state) then you should override onSaveInstanceState() and onRestoreInstanceState()
If you really want an answer to your question, then here it is:
While it is running onDestroy(), your app has (probably) as much time as it would like to - the fact that it is even running onDestroy() means that the OS did not select it to be killed. But it will most likely not matter: for one, onDestroy will never be run in most apps, and if the OS changes its mind and decides that your app must die, it will kill it even if it is running onDestroy.
http://developer.android.com/guide/practices/design/responsiveness.html:
In Android, the system guards against
applications that are insufficiently
responsive for a period of time by
displaying a dialog to the user,
called the Application Not Responding
(ANR) dialog
The ANR dialog will normally pop up if your application is un-responsive for 5 seconds. As pointed out by jhominal, the onDestroy() method is probably not where you want to do your clean-up/save preferences/etc.
Regardless of where you choose to do this, be it onDestroy(), onSaveInstanceState() or in onPause(), I believe the general 5 second rule will apply. If what you're doing takes more than 5 seconds, the ANR dialog will show and the user can choose to force-close your app.
Edit:
If your application is in the background, it might be (probably?) that it is killed directly without the ANR dialog being displayed if you violate the 5 second rule. But I do not know this for sure, only assuming.