SharedPreferences not refreshing? - android

I'm using sharedPreferences to store some simple data that I access periodically. I've noticed that when I "put" something using the SharedPreferences.Editor (I do call commit()) when I later try to access the prefs with prefs.getAll() my newly added item is not there.
Oddly, if I close my app and fire it up again, it appears. It's like the prefs are not refreshing while my app is running. Is that by design? What gives?
BTW, I've noticed the same behavior while doing editor.remove("key"). I remove something (and call commit()), and when I call getAll() the deleted item is still in the Map returned. If I try to delete it again, my app force closes.
I must be doing something wrong. Any help is appreciated.
Thanks,
Bobby

This should not happen if you use SharedPreferences the right way. The only two scenarios I can think of when this happens is if:
commit() returns false (yes, it does really have a return value) or
you are trying to use the SharedPreferences across multiple processes, which is not supported yet.

Ok, my blunder. I was displaying the list of prefs in a freaking dialog. I missed that the dialog create was only called once so it never updated with my new values. Gah!
Thanks anyway!

Related

Where to do put the code that do things one time upon app install

I have some DB work that I need to be done once when the app is installed and ran the first time.
I know I need to use the SharedPreferences to track this to make sure it is done once. But my question is when this work should be done (or the methods that do that should be called). Is it done on the OnCreate() of the home page of the app (first screen) or is done in a derived class from the Application class?
Right now I am doing it in the application class, however the only down side is that the I can't display ProgressBar to indicate things are being worked on (probably because there is not Context attached yet). But I want to confirm that this is a correct place to do preliminary things in the first place
Thank you
I would do it in the onCreate() using AsyncTask which will perform it in the background and it can post back to the, what you call, "first screen" the progress, and you can display progress bar.
try this
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if(!prefs.getBoolean("firstTime", false)) {
// run your one time code
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("firstTime", true);
editor.commit();
}

Android - shared preferences set in an AsyncTask onPostExecute() not always set?

I have some code that works 98% of the time, and 100% during my own testing so I can not really reproduce the problem other than having user devices experience this issue.
What I do in onPostExecute() is set a parameter like this:
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( AddProblemActivity.this);
prefs.edit().putString("recent_problem_id", result ).commit();
and then go to the next activity:
Intent myIntent = new Intent(AddProblemActivity.this, ProblemActivity.class);
AddProblemActivity.this.startActivity(myIntent);
and then try to get that parameter there like this:
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
ProblemActivity.this);
// display a loading message before problem loads.
String recent_problem_id = prefs.getString( "recent_problem_id" , null );
if ( recent_problem_id == null )
{
// Sometimes it is null!
}
Would anyone know why this happens?
Thanks!
If you are trying to pass the data to a new activity, why not put it as a String extra in the intent? Then, get that String from the intent in the new activity. If you still need to store it, you can do so in the new activity's onCreate() after it pulls it from the intent.
Intent myIntent = new Intent(AddProblemActivity.this, ProblemActivity.class);
//Add results here
myIntent.putExtra("RecentProblemId", result);
AddProblemActivity.this.startActivity(myIntent);
Then, in the onCreate of your new Activity, do:
String recentProblemId = getIntent().getStringExtra("RecentProblemId");
Now, if you still need this information stored, do:
if(recentProblemId != null){
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
ProblemActivity.this);
prefs.putString("recent_problem_id",recentProblemId).commit();
}
I know this doesn't exactly answer your question as to why the String isn't always being committed to the preferences in onPostExecute(). However, the best practice for passing information between activities is via Intents and extras.
My guess as to why it may not always work for some users, is that their devices are not done writing the data to the shared preferences file before the new Activity starts and tries to read from that same file. Hope this helps.
First of all, see Raghav Sood's answer.
There is one delicate moment. You might start executing your AsyncTask than rotate the device. Activity will be recreated and in PostExecute you'll have wrong context so your preferences won't be saved.
If it's true you should use onRetainNonConfigurationInstance() to save appropriate task's instance.
I'm not sure about this, but I think the problem might be due to the difference in the Context you're passing. You're using the Context of AddProblemActivity first, and then the Context of ProblemActivity. Try using a set preference, like a filename one:
SharedPreferences prefs = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
Note that getSharedPreferences() is a method from Context, so you'll need to have a reference to an Activity or maybe Application Context in your AsyncTask to be able to use it.
Seems like your code is fine and there's no reason why it shouldn't work, the only reason will be some defect which is probably device related. My thoughts are since the Shared prefs are saved on local storage something can go wrong in the process.
As advised in the comments, it will be a must to add a device type log,
I would recommend you use "ACRA" - http://code.google.com/p/acra/ that can give you detailed reports with minimum effort (pay attention you can send a report not necceserily only on app crash).
Take a look at this thread, he shows a problem that maybe you are experiencing as well:
SharedPreferences will not save/load in PreferenceActivity.
If it's the case, a solution will be to handle the saving of this persistent data manually on the local storage or use a DB solution. Good luck :)
I think the issue is due to the shared preference setting not being written to your file system yet when you try to access it from your second activity. You mention that you write the setting from the onPostExecute method (of an AsyncTask perhaps?). When you start an AsyncTask there is no guarantee that it will start immediately. The only guarantee there is, is that it will start in a background thread. The platform can and will decide when to actually run the background thread, depending on system load, file system blocks or so. It might very well be so that your AsyncTask hasn't been started yet when you switch to the second activity (and hence the onPostExecute method hasn't been called yet).
Saving shared preferences are tricky as they write to the file system. You might end up blocking the main thread if you aren't careful. The SharedPreferences.Editor object has an apply method as well which will update the in-memory cache of your shared preferences immediately (making the changes available at once) and kick of a background thread to save the actual value to the file system as well. So my tip would be that if you have the possibility, you should try to call the apply method (from your main thread) instead of the commit method from (what I assume) a AsyncTask. The apply method requires API level 9 or higher.
For your reference: http://developer.android.com/reference/android/content/SharedPreferences.Editor.html
Edit:
The commit method will return a boolean value depending on the result of the write operation. You could (should?) check that return-value in order to at least be able to take correct counter measures on failure (like show a "Couldn't save your setting, please try again" toast or something).
Cheers,
--dbm
I could be wrong. But I believe a friend of mine had a similar problem once. I was stuck on this problem for hours. The results for more like 30% of the time it wouldn't work. I believe that the onPostExecute() runs on a separate thread when the Intent is instantiated and the activity is called. This is because an AsyncTask is implemented on a separate thread. Depending on the device, this would be called more likely then not. Our tablet it rarely happened, on the smart phone it would occur more commonly.
You can test this by debugging the application and looking at the AsyncThread thread and see when the call is made.
Yes, it is better to send the variable via the putExtra().
I hope this helps you understand why this occurred.
The commit action of SharePreferences is synchroneos so I don't think the fact that you are starting the new intent should effect it, only thing is that the commit action isn't fail safe, it can fail.
http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#commit()
Returns true if the new values were successfully written to persistent
storage.
Maybe you should check that return value to make sure you managed to save the result.

how to save and retrive data from the last run of an android application?

I have to create a small android application for my college course work which presents 10 maths problems and take answers from users to calculate the score.
The program is supposed to have a main screen with "new game" button and a "continue" button.
How do I program to save data during the application run and retrieve them from the stored place to continue from that point if the user presses continue button? (what sort of a method I should be looking at for such a task? )
Thanks in advance.
Just use preference to store and retrieve value in the code.Here is the snippet
//Set Preference
SharedPreferences myPrefs = getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
SharedPreferences.Editor prefsEditor;
prefsEditor = myPrefs.edit();
prefsEditor.putString("REFKEY", valuetobestored);
prefsEditor.commit();
//Get Preferenece
SharedPreferences myPrefs;
myPrefs = getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
String output=myPrefs.getString("REFKEY", "");
It depends on the kind of data you want to store. If it is really basic, you would want to store them as name value pairs in the onSaveInstanceState method or as Preferences in the onPause method, if it is a bit more complex, you might want to store in a SQLiteDB.
The guide says
the method onSaveInstanceState(Bundle) is called before placing the
activity in such a background state, allowing you to save away any
dynamic instance state in your activity into the given Bundle, to be
later received in onCreate(Bundle) if the activity needs to be
re-created. See the Process Lifecycle section for more information on
how the lifecycle of a process is tied to the activities it is
hosting. Note that it is important to save persistent data in
onPause() instead of onSaveInstanceState(Bundle) because the latter is
not part of the lifecycle callbacks, so will not be called in every
situation as described in its documentation.
This is how you save data in onSaveInstanceState: Saving Android Activity state using Save Instance State
This is how you can save data in Preferences: Making data persistent in android
Just use SharedPreferences. Check this link out for more details. 2 early in the morning to give you an example of my own :P
How do I get the SharedPreferences from a PreferenceActivity in Android?
The preferences lasts as long as the application is installed on the device. One you delete if , it removes them as well.
Another cool thing you might want to know, if you want to check if your app is at it's first run, EVER, then just check a boolean value stored (or not stored on the first run) on the device. :) If there isn't one (it will return the default value), then just change it's value to true or something and as you'll check it every time the app runs, you'll know it's not the first run :)
Hope this helps, cheers.
May be this is not the best solution.. but this is a way to get required functionality..
in on click of continue button put this code
finish();
Intent k=new Intent(youractivitytivity.this,youractivity.class);
k.putExtra("qno",x+1)<---- next question number to appear on screen(x is the present question number)
k.putExtra("score",bool)<--- if the answer is right or wrong)
startActivity(k);
then in the on create of your activity.. get extras and check which question you have to display...
i think you have an array of 10 questions..

Where should you call PreferenceManager.setDefaultValues?

In order to initialize preferences with default values from XML file describing the preferences, I can call PreferenceManager.setDefaultValues(this, R.xml.preference, false). Sounds simple, but I'm not quite sure when exactly should I call this?
As I understand from the docs, the above call is only needed once, in situation when no preferences are set yet. As a result of this call, preferences residing in /data/data/<myapp>/shared_prefs are going to be set, so all subsequent attempts to read preferences will get me the default values. Logically, setDefaultValues should be called in every single code path that might be executed without preferences being already initialized. Over time, this turned out to be multiple places - main activity, another activity, background service, small BroadcastReceiver handling system messages... Right now I've put call to setDefaultValues in onCreate() for my Application object, as I'm already using it as convenient singleton for other things.
Questions:
Do I have a guarantee that every time my code executes, Application object will be created and onCreate will run?
How are you dealing with this problem? One other way would be to hardcode default values into getFoo(key, defValue) calls, but that effectively scatters your default settings across whole code.
EDIT: Essentially, I don't know which solution is worse: calling setDefaultValues every time I access prefs in given code path, or calling it in some common place (like app's onCreate) every time, no matter whether I need it or not.
I'm going to delete my original answer and answer the questions that you actually asked.
Yes, the Application object's onCreate will be executed at the start of every process. Keep in mind that doesn't guarantee it will be run each time you start your main activity. If Android still has your process running it will use that again (e.g. you still have a service running). So yes what you're doing will work and you're correct in observing it won't blow up.
I'm dealing with this problem by subclassing SharedPreferences (let's call it MyPrefs -- that's not what I call it but that's not important). The key features of MyPrefs are:
encapsulation of get/set methods instead of directly accessing the key names
Handling code for loading defaults. I'm being a little lazy by using a static boolean instead of an AtomicBoolean to tell me if the defaults have been loaded.
Having said that... it works for me, but if you're almost certain you'll be calling the SharedPreferences every time your code runs where you're at works as good as any.
Hope this helps more than my previous answer.

SharedPreferences Problem

i am using SharedPreferences in my code that will store last state of my check box. when i focefuly stop my application through setting>> application it dosn't save it's previous state. what is the problem ...
Are you calling Editor.commit() when you make a change?
Be sure you implement the OnSavedInstanceState function and save all you want to be saved in there.

Categories

Resources