Any downside to saving preferences frequently in Android? - android

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.

Related

LifeCycles getting called when app is forcefully killed

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.

Why onDestroyed() not called after app pushed out from memory?

1) Activity is on onStop() state.
Example: overview button tapped.
2) Working with phone till android pushed out app from memory.
Example: gaming
3) Overview tapped and app tapped then crash
Any solution to destroy it when pushed out from memory?
There is no assurance that onDestroy will ever be called. Do not depend on it, it should be used for opportunistic cleanup only. Especially in the case of a crash, it will NOT be called, because the app may not be in a state where its safe to do so.
You can do a couple things. Manage your absolute necessary clean up in the Application file. (low memory) callback can call the same method.
One idea would be to have a baseclass or abstract model where you keep a reference to the the active version in Application class. Then if low memory is called, you can manually call your (selectedActivity.OnDestroy).
It's a work around to make sure that a low memory calls your cleanup. You can also add one for unhandledException listener to make sure a crash can call your cleanup as well. Depends on how important your final cleanup is in the event of app closure.
If the cleanup is too heavy or time intensive, you can simply set a "bad closure" flag in a DB or shared pref that you check on startup and do your cleanup on the next app launch.

When to save data to database, onPause() or onStop()?

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.

How to save state of activity on android on back key press

I'm having an issue with an android app I'm writing that seems like it should be a common issue but I can't find any information on it.
I have a scoreboard activity in my app that just stores a grid of scores in textviews, it's the kind of thing that the user will update, then hit the back key and look at some other activities, then come back later to update it, leave again, etc...
The problem is that every time they leave and come back the whole activity gets reset, losing all their scores. I can't use saveInstanceState because it isn't called on back key pressed. I really don't know where to go from here except for saving thew hole grid in sharedpreferences, I feel like there has got to be a better way though
Any ideas?
In general, you need to save any state information in onPause(), and recover it in onResume().
I was under the impression that various state information is kept automatically when you close the App, and automatically restores itself when start it back up again (until Android removes the App from its memory to make space, calling onDestroy()).
If I were you, I would store the grid in SharedPreference. It really is the most reliable solution.
You can also use the details in this topic:
https://stackoverflow.com/a/151940/503508
May this help you
When the user presses the BACK button, your foreground activity is destroyed. That activity will be called with onPause(), onStop(), and onDestroy(). That activity object will then be garbage collected (unless you introduced a memory leak).
onSaveInstanceState() will be called periodically if there is a chance that the activity will be destroyed shortly but in a way where the user might be able to navigate back to it. The prominent case for this is during a configuration change, such as rotating the screen.
What you should be doing in onPause(), if anything, is persisting data using "sqlite, file saving and other persistance methods". Once onPause() is called, there are no guarantees that this activity will stick around, or that your entire process will stick around. Anything you value, therefore, should get written out to persistent storage.
The "state" for onSaveInstanceState() would be things that affect the activity's UI but are not part of the persistent data model. Much of this is handled for you automatically by Android's built-in implementation of that method (e.g., the text in an EditText), but you can add your own information to the Bundle if you wish. However, your instance state is not your data model, so anything you want to stick around needs to be written out to persistent storage.

Why should Android data be committed/read in onPause() - onResume() rather than in onStop() - onStart()?

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.

Categories

Resources