I know this question has been asked a million times, I myself though that I already knew the answer and that the correct one was that the only guaranteed call is to onPause(), so you should save your data there.
However, in many places of android documentation they always suggest not doing heavy work (such as writing data in database) in the onPause() method as it will delay the transition between the activities.
According to Android Developer Guide in Table 1
onPause(): This method is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, and so on. It should do whatever it does very quickly, because the next activity will not be resumed until it returns.
Killable: YES
Then according to Android Developer Reference Guide in the similar table.
It says the same thing but:
Killable: Pre-HONEYCOMB
And they add a little note that says:
Be aware that these semantics will change slightly between applications targeting platforms starting with HONEYCOMB vs. those targeting prior platforms. Starting with Honeycomb, an application is not in the killable state until its onStop() has returned. This impacts when onSaveInstanceState(Bundle) may be called (it may be safely called after onPause() and allows and application to safely wait until onStop() to save persistent state.
Killable
Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may killed by the system at any time without another line of its code being executed.
FOR POST-HONEYCOMB (i dont care about earlier versions):
So, is it OK to assume that any Android device (including different ROMS) will ensure a call to onStop on the activity? And this is the best place to make any time consuming storage writing of the App?
Note: This is extremely confusing as most answers here, sites, books, and even online android tests take as a correct answer that you should save it in onPause and NOT in onStop.
When to save data to database, onPause() or onStop()?
Either. They are nearly identical, particularly on Android 3.0+.
If the activity that is taking over the foreground is a typical full-screen activity, so that the earlier activity is no longer visible, onPause() and onStop() will be called in rapid succession.
If the activity that is taking over the foreground is themed to be more like a dialog, where the earlier activity is still visible, onPause() will be called, but not onStop(), until such time as the activity is no longer visible (e.g., user now presses HOME).
Most apps aren't worried about the "themed to be more like a dialog" scenario, in which case onPause() and onStop() are called one right after the next, and you can fork your background thread to save your data in whichever of those makes sense to you.
However, in many places of android documentation they always suggest not doing heavy work (such as writing data in database) in the onPause() method as it will delay the transition between the activities.
The same is true of onStop(), as both of those methods are called on the main application thread.
So, is it OK to assume that any Android device (including different ROMS) will ensure a call to onStop on the activity?
Both onPause() and onStop() will have the same characteristics from the standpoint of process termination. Either both should be called (normal case) or neither will be called (e.g., you crash, the battery pops out the back of the phone).
And this is the best place to make any time consuming storage writing of the App?
Either onPause() or onStop() are fine places to trigger the work, done on a background thread, to persist your data. If you prefer to do that work in onStop(), you are absolutely welcome to do so. Personally, I'm an onPause() kind of guy.
If you want more safety, storage in onPause.
If your data is so big that you have to storage it for several seconds, you may open a background Service (e.g. IntentService) to save.
You can also check the system version in your code and choose when to save. if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.ICE_CREAM_SANDWICH){}
In most situations this rule of when to save will not be changed by some customed os. But of course there can be some other os which certainly changed it. So the most important thing in android development is that u need to know that everything can be different in different phones.
I know this question is prehistoric, but it seems like people like me still happen to land on this question. So I guess it may make sense to add an answer I found in the documentation, which states:
To save persistent data, such as user preferences or data for a database, you should take appropriate opportunities when your activity is in the foreground. If no such opportunity arises, you should save such data during the onStop() method.
source
But wait, there's more:
Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may be killed by the system at any time without another line of its code being executed. Because of this, you should use the onPause() method to write any persistent data (such as user edits) to storage.
source
So wrapping up, it seems like persisting data onPause() is the best thing to do.
Related
Im using in my app the onDestroy method to clean up data.
Google's documentation says documentation
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.
Such a situation is swiping the app out of the recent tasks list.
So in this case, data and other user important information must be saved in onPause or orStop().
But according to this link, none of the lifecycles get called.
So where do we save our data?
But according to this link, none of the lifecycles get called.
That answer is somewhat misleading. Your foreground activity should no longer be in the foreground when the user brings up the overview screen (recent tasks list). onPause() and onStop() will be called on that activity as a result. You can test this by overriding onPause() and onStop() and logging their calls.
So where do we save our data?
That depends a lot on what you are building.
In some cases, save the data when the data changes and the user indicates that they want to hold onto this data.
In some cases, save the data periodically. For example, in a game, you might save the game state every so often, so the user can pick up the game from where they left off.
In some cases, using a lifecycle method (e.g., onStop()) as a data-save trigger can be OK, but other times not. Saying "we will save the stuff that the user has typed in when we get called with onStop()" might be fine. Saying "we will go ahead and charge the user's credit card when we get called with onStop()" might not be fine.
I'm trying to execute some code whenever my activity is killed, but not when it's simply moved to the background (so just calling it in onPause() isn't a solution), and I understand onDestory() is not guaranteed to be called. I've been searching all over and haven't found a way to do this. How can I go about tackling this problem? Is it possible?
Nothing. You can never be guarantied to be called when an app ends, because it can always be terminated abnormally- it could crash, the battery could be pulled out, etc. onDestroy is the closest you can come. But you should never write a program that requires cleanup at termination time.
I'm not sure, but I suspect you've got a few issues which you've conflated into one large issue;
As I read this question you have 2 or 3 concerns:
1) You want to garuntee something happens when the app exits.
2) You have state you want to maintain during onPause() but not after onDestroy()
3) You presumably have some content which should not persist between application usages.
Some answers:
1) As Gabe points out - there is no guarantee anything will ever be called. I can pop the back off the device and pull out the battery. Your calls aren't going to happen.
2) You might try onDestroyView() for this case. It won't be called in many circumstances in which onPause will be (for example when an alert dialog is shown), but will be called in others (when you replace a fragment with another fragment for example).
3) This issue makes me think you may want to reconsider your method of storing/saving this information. If you don't want it to exist on the system when you app isn't in use, it is best to never write the data to the filesystem. (Due to 1). Other options are keeping it in memory. You could also use shared preferences/preferences mechanism but this will still exist on the filesystem until your app is removed.
The documentation suggests that the data should be committed/read in onPause()/onResume().
Yet when the application is no longer in the foreground, its data structures remain intact, which suggests that one could delay committing/reading data until the application is no longer visible, i.e. in onStop()/onStart(). Particularly since onStop() is guaranteed to be called before onDestroy().
Is it perhaps the case that either approach is suitable? Is the documentation giving here merely a guideline?
Update
Suppose your application needed to save relatively substantial data, say edits to a large image. One would then surely not write/read in onPause()/onResume(), lest the user experience become sluggish. One would in that case choose instead to write/read in onStop()/onStart(). Is that true?
The problem with using onStop is that you have no guarantees on when it will be called since the only sure thing is that it will be called before onDestroy. If you wait until onStop to commit your data it may be to late for another activity to show/use any of those changes. Same thing applies to onStart, your activity may not need to be restarted if it was just in the background so you'll have stale data. Using onResume and onPause guarantees that your data will always be current, commits are made as soon as the activity goes to the background and new data is loaded as soon as it becomes visible.
Yes, it is just a guideline (and generally a good one). It is up to you exactly when you want to commit changes. I personally like to create Store Objects that allow a simplification of Databases or SharedPreferences, and when a change is made, I commit those changes immediately. For simple data storage, this will be quick and invisible to the user. For large data sets, this may take more time, and you may wish to make those writes on a time interval, as well as in onPause.
As for when to read - you can read whenever, but again longer reads will often affect the user experience, unless you have taken care of it in another thread, such as with an AsyncTask.
To Further answer your update:
It depends on the developer, however I would write in onPause() and if necessary, read in a separate thread, probably initialized with onResume(). I may also write data out on a scheduled interval using a Timer thread, depending on how it would affect the user experience for the current session, and if it would be catastrophic for the phone to turn off and lose all data before onPause() is called.
The true answer to this is, onPause is the only method you are guaranteed to get called before Android can destroy your process. If a user leaves your app to take a phone call, and Android decides to close your process, its entirely legal for you to only get an onPause call. If you hadn't saved your state there, when the user hits the back button, you will end up recreating your activity in a different state than the user left it in.
I have a rather small amount of state in my Android app that I wish to ensure is saved persistently. It's tiny, clocking in at about 50 characters.
Looking at the Android Storage Options page, they give a few choices, the simplest which seems to be shared preferences. Now these aren't actually application preferences, more a short indication of where the application is at.
My worry is that preferences are expected to change infrequently and the likely use case may not therefore handle a lot of changes. By a lot, I mean peaking at about once per second, depending on user activity.
So I want to make sure of two things.
The first is that the sample code on that page linked above has the preferences being written out in the onStop method. Are we guaranteed that this will run when the application exits, no matter what?
If so, I can maintain the state in-memory and use it to save persistently, then this frequency-of-updates problem disappears.
Basically, I want to ensure there's no way my application can stop without having saved its state (short of catastrophic failure of course).
Otherwise, I'd rather save this state whenever it changes so as not to lose anything.
Second, and this is important only if I have to save state every time it changes, are there any downsides to saving preferences up to once per second? As mentioned, I'm not sure if it's designed for frequent updates.
If the application exits normally, onStop() is called. If the application is backgrounded (ie with the home button/getting called) onPause() is called, which calls onStop(). If the application exits (ie with the back button), onPause() is called, which calls onStop(), which calles onDestroy(). However, when the application crashes (ie through a nullpointerException, onStop() is not called, the application just crashes).
Personally, I mostly use a settingsContainerObject of some sort, and just write my preferences to the internal storage in the onStop() method. Works pretty well.
In short: yes, onStop() is always called when the application is backgrounded or exit.
You can also stop the application in try/catch blocks, to always save your settings.
Can anyone give a short overview of the cases when and how an activity is killed by the runtime? I'd like to know the difference between the paused and stopped state. What could force the system to destroy a paused activity, exactly the same (low memory) reason as if it was stopped?
I think if an activity is paused because of an incoming phone call (which suddenly causes a low memory situation) the system simply prefers to release ressources of stopped activities. But how is that done? When does the system "kindly ask" the activity by calling finish() and when not, and when does onDestroy() still get called?
Most of what you asked is described pretty well by the documentation, but I think I can clarify a couple of things.
I'd like to know the difference
between the paused and stopped state.
Visibility. The two states are distinct because a paused activity may only be partially obscured by another activity such as one that's had the Dialog theme applied. That requires keeping whatever resources are needed to maintain visual state. Stopped activities can jettison those resources which could make the difference between the activity being destroyed or preserved if resources are tight.
I think ... the system simply prefers
to release ressources of stopped
activities. But how is that done?
It has to. Stopped activities are completely invisible, which makes them better candidates for killing than those that are still contributing something to what the user sees. I've never seen Android yank a paused-but-partially-visible activity out from under one that's resumed, but I suppose it could happen under the right circumstances. The system knows each activity's state because it's what's directing them there.
When does the system "kindly ask" the
activity by calling finish() and when
not, and when does onDestroy() still
get called?
The system will do orderly destruction when it can, but the API only guarantees are that an activity will ever see onPause() and onSaveInstanceState().
ETA: The exact reasons why activities are removed from the stack are in the source. You shouldn't depend on those reasons being universal truth, because there may be a future version of Android that makes its decisions differently.
Par for the course, I see! I see some valuable information, mixed with expensive misinformation. No, the online docs do NOT every specify exactly under what circumstances the process is killed. This is deliberate, since it is subject to change without notice. Sure, the most common reason for onDestroy() to be called is that the system is running out of memory, which is less common on newer phones (since they have so much memory). But there is no guarantee that that be the ONLY reason it is called.
But yes, the 'contract' between Android and the developers is that if you follow the rules, implementing the needed lifecycle callbacks when they are needed, then it will work, and you do not NEED to know exactly under what circumstances onStop(), onSaveInstanceState() and onDestroy() are called.
Now unlike Google, I will admit that the wording of the contract is somewhat vague at points. This is because, among other lesser reasons, they use terms that have a standard industry meaning, such as 'foreground', but they use them in slightly altered senses. And the alteration is either never explained or explained only in obscure places. It also doesn't help that the diagram purports to show "the paths an activity may take between states", yet fails to show that onDestroy() can be called at many times, even bypassing the transition from Resumed to Stopped. Yet the text clearly describes that possibility.
This is why, unfortunately, reading the Application Lifecycle section of "Application Fundamentals" is simply not enough. Instead, one must also read the Javadoc for EACH of the callbacks under that for Activity, and also the section of "Application Fundamentals" on Processes.
After that, it is enormously helpful to put Log.d statements in each of the callbacks and watch the logcat output while you cycle your application through the lifecycle. But even then, do not rely on lifecycle events taking place in the order you see in logcat unless you can find justification for it in one of these online docs mentioned above.