SharedPreferences will not save/load in PreferenceActivity - android

EDIT: The problem described below was due to a very peculiar device issue not caused by any coding-related problem.
I have a preferenceActivity in which I have many checkBoxPreferences.
The checkBoxPreference is suppose to save the the default shared preferences file, and then be called again when I open the app in order to update the UI.
This does not happen like it's suppose to.
If I close the app and open it back up, my values remain like they are suppose to, but if I use task manager to end the app or if I power cycle the phone (when the app is not running) then the defaultValues are called again.
So, I created a SharedPreference in my onResume() to test it.
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
I then check to see if there is a key in that sharedpreference.
pref.contains("myCheckBoxPreference");
When I close out and open it back up, it returns true. if I close with the task manager or power cycle the phone off and on, then that returns false.
So, I tried manually setting the SharedPreference
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("myCheckBoxPreference", myCheckBoxPreference.isChecked());
editor.commit();
and then I called that when the checkboxpreference value changed. I also tried calling it in onStop and onPause. Still, if I close the app and open it back up, pref.contains returns true, but if I power cycle the phone off and back on, it returns false.
So I then tried using a SharedPreferences file.
In the class declaration:
public static final String PREFS = "prefs";
And in the onResume():
SharedPreferences pref = this.getSharedPreferences(PREFS, 0);
Same behavior, pref.contains still returns true if I just close the app and open it back up, but it returns false if I power the phone off and back on.
I then tried changing the key value of myCheckBoxPreference to something that did NOT match the xml key for the CheckBoxPreference, and it still had the same effect.
And I uninstalled the application from the phone, then powered the phone off and back on, and then re-installed, and it still has the same effect.

I just solved it, I'm pretty sure. There's no code error on my part, and there is no issue with my app whatsoever (I don't believe, anyway.)
I created a new project called "testproj", then I copied ALL the code from my settings PreferenceActivity, pasted it into the TestprojActivity, and I copied the code from the xml it relied on, then pasted that into the main.xml of TestProj.
I then installed TestProj on the Samsung Captivate, changed the settings around, cleared the ram through RAM management (a function of the custom ROM I have), and the settings stuck. I then power cycled the phone and the settings were still there like I'd configured them.
They stayed both when I manually set them using:
PreferenceManager.getDefaultSharedPreferences();
and without manually saving them to the SharedPreferences.
Since it is not my phone, I haven't tried it yet, but I assume a Factory Data reset would fix it completely
EDIT: I was able to test on both a new Samsung Captivate and a Samsung infuse, and it worked.
I wasted a lot of my time trying to figure this out, and I hope it helps someone else. :)

I encountered a possibly similar problem on a Samsung Galaxy S, where the permissions for the preferences XML file had somehow changed/corrupted.
The log revealed some host process was failing to read the file, causing all the settings to reset to their defaults. I don't recall the exact error message, but it was along the lines of "permission denied for /path/to/preferences/file.xml".
The resolution for me was to delete the application data through Settings, Applications, Manage Applications, MyApp, Delete data. This deletes the preference file associated with the app and the problem instantly disappeared.
I assumed it was an isolated event, as I've not run into it again on a variety of Android devices (including the Galaxy S II).

On the client's main test device I came across the very same issue. The Device used is a Samsung Galaxy S with SDK level 8 (2.2.1).
The strange behavior is that either SharedPreferences are not saved, or, as after a factory reset, they're too persistent, that is to say they are not deleted after having reinstalled the application.
Due to the current distribution of 2.2.x, and the number of Samsung Galaxy S devices sold being several millions, the probability of an occurrence of this issue is significant.
So it can be considered as crucial to implement a workaround for saving preferences.
For collecting detailed characteristics to isolate this workaround in a sharp-edged way, could everyone who is also facing that issue please provide the corresponding kernel version (System.getProperty("os.version") here?
I was thinking of something like this:
// !! I know that 2.6.32.9 is not yet correct. This would be a false positive !!
if ((System.getProperty("os.version").startsWith("2.6.32.9"))
&& (android.os.Build.DEVICE.contains("GT-I9000")))
useInternalStorage();
else
useSharedPreferences();
I can post the real code here also once it's ready and someone is interested.
EDIT: some additional information:
Devices facing that issue:
Property | Values
---------------------------------+------------------------------------
Build.DEVICE | "GT-I9000T"
Build.VERSION.INCREMENTAL | "UBJP9"
Build.VERSION.RELEASE | "2.2.1"
Build.VERSION.SDK | 8
System.getProperty("os.version") | "2.6.32.9"
Similar devices NOT facing that issue:
Property | Values
---------------------------------+------------------------------------
Build.DEVICE | "GT-I9000"
Build.VERSION.INCREMENTAL | "AOJP4"
Build.VERSION.RELEASE | "2.2"
Build.VERSION.SDK | 8
System.getProperty("os.version") | "2.6.32.9"

Try clearing the editor before you set your values. I had the same problem and it worked for me.
Example:
Editor e = PreferenceManager.getDefaultSharedPreferences(getParent()).edit();
e.clear();
e.putStringSet(key, value);

It is possible to work around the issue of permissions by using sharedUserId which should be the same for any of your signed apps.
http://developer.android.com/reference/android/R.attr.html#sharedUserId

I too had a problem with saving and then retrieving data. I had my Save and Load code in a class that extends Application because I wanted a single instance of my data. I could see the String being saved, no errors in LogCat and yet when I try to load it, again with no error, my String is empty. I never checked whether the data actually went into the file so I have no idea whether there was a failure on Save or Load or both.
My code was more or less as follows: (comboToSave is simply a string generated by Gson from a simple data class)
in one method to save:
SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(getString(R.string.prefCombos), comboToSave);
editor.commit();
in another method to load:
SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
String loadedComboText = sharedPref.getString(getString(R.string.prefCombos), "");
After lots of head scratching and not knowing what to do I changed the code that retrieves the sharedPref value from
SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
to
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
There is some more here on the difference between the two (although in my case it seems exactly the same)
Still the result on my Galaxy S3 was the same. However, testing both versions on other devices, including VDs (virtual devices) worked.
In the first version of the code I passed the Activity from the calling activity; for save from the activity where the final bit of data is collected from the user, and for loading from my main activity so that I had it ready when the app is started.
I played with uninsalling the app and re-intalling, turning the device off and on again last night to no avail.
I have now moved the save and load methods from the application class to the activity where I complete the input i.e. both load and save code is now in the same activity. I have tested this with both variations of the code and they both work. I get back what I save. I then moved all the code back to the Application class and it works; this leads me to believe that somehow with all the installing/uninstalling I somehow managed to get it working. Point is: the code is correct - if it does not work the device and/or settings are probably to blame

I have the same problem, and i suffered from it for a while , finally i found the solution ,
and it is so easy , just pass the direct reference of the activity , and do not use any general context
public SessionManagment(Activity mContextActivity){
// this.contextActivity = mContext;
sharedPrefSession = mContextActivity.getSharedPreferences(
Constants.SHARED_PREFERANCES_LIGHT_TIGER_SESSION_FILE_NAME,
Context.MODE_PRIVATE);
}//enden constructor
the code above is the constructor of the class that i have written for session management , and
and when i call it in the code in the main ActivityFramgment in a AsyncTask i call it like this
SessionManagment sessionManagment = new SessionManagment(referanct2thisActivity);
where referanct2thisActivity is defined in "onCreate" function of fragment activity like this
referanct2thisActivity = this;
hope that will help others in the future

Related

Weird thing on sharedPreferences while loading the highest score

I am using SharedPreferences to store and load the highest score on my game. The problem that I found is that when I close the emulator from the 'X' mark it didn't save the highest score, but if I firstly put the app in the background and then close it (within the emulator or from the 'X' mark) it will save and load the best score. Here is the code that I use:
//save the highscore
SharedPreferences prefs = this.getContext().getSharedPreferences("BEST", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("key", best);
editor.commit();
//load the highscore
SharedPreferences prefs = this.getContext().getSharedPreferences("BEST", Context.MODE_PRIVATE);
best = prefs.getInt("key", 0);
note: I have tested the game on two acutal devices ( LG Optimus L2 and Samsung Galaxy A3) and on both of them everything works normally. It is something that i shouldn't worry about?
EDIT: I forgot to mention that I had to use "Clean Project" after I renamed the folder of the project directly and from here I encountered some errors. Maybe that has something to do with it.
Whether your score gets saved depends on where you run your code to save it (which looks completely fine). If you, for example, save it in the onStop() method of an Activity, then putting it in the background will save it properly.
Shutting down the emulator by closing its window probably kills it quite violently, in which case it can very easily be the case that your app doesn't receive the lifecycle callbacks it normally does, it just gets terminated immediately, hence your code that would save to SharedPreferences doesn't get to run. On a real device this sort of immediate shutdown would be the equivalent of shutting down the phone by holding the power button or taking out the battery, which is not something you can prepare for.
TL;DR: this seems normal, I wouldn't worry about it.

Sharedpreference between applications with the same sharedUserId

I'm working on a project where I have a core application and multiples plugins which are different apks. I would like to share some data between my different modules (for ex. the name of the user or his email address). I tried to give them all the same sharedUserId by adding it to their manifest :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.giom.mymodule1"
android:sharedUserId="com.giom">
My modules are really similar and both save and try retrieve their sharedpreferences the same way :
Context mainAppContext = getActivity().getApplicationContext().createPackageContext("com.giom.mainapp", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
SharedPreferences sharedPreferences = mainAppContext.getSharedPreferences("sharedpreferences", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
sharedPreferences.edit().putString("EMAIL", email).commit();
And
Context mainAppContext = getActivity().getApplicationContext().createPackageContext
("com.giom.mainapp", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
SharedPreferences sharedPreferences = mainAppContext.getSharedPreferences("sharedpreferences", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
String email = sharedPreferences.getString("EMAIL", null)
Both codes are from my PreferenceActivities which are FragmentActivity. The problem is this seems to be working ; for example if I change the value in one of the modules and reboot the phone the other is changed. But if I open one of the activities, then the other, change the value in one of them and come back to the other I will still get the old one until I reboot. It's working like if there was some kind of cache...
My intuition is that I'm not using the right Context and that I should replace getActivity() by something else but I don't know what...
Thanks in advance for your help.
PS: I read that this method was depreciated so if you have any idea of how I should share my data feel free to tell me :)
Ok, found the answer here : https://stackoverflow.com/a/11025235/3628452
The getSharedPreferences method appears to check for a .bak file to
load the preferences from. This is why it says in the documentation
that it will not work across multiple processes; to minimize I/O, it
loads the prefs ONCE when you grab them and only backs them up when
you close your application/activity
Which means that if I don't open/close my modules I'll still have the data from the bak file from when I opened it...

Writing to shared preferences too slow?

I have created a service that writes some information about a widget once a user places it on home screen(the info is picked up from the confutation activity)..i also write down the number of widgets the user has set up.
Once the user removes the widget i delete that info in the shared preferences.
What i have experienced is that if user places for example 2 widgets, then removes one, then places one again, doing all those actions fast, the shared preferences file gets inconsistent values in it. Sometimes it works ok but most of the time i get stuck with wrong values in it.
I am using apply(), i've tried with commit but same thing happens.
The values i store in the shared preferences are crucial for the system to work, without it the widgets are useless since they are backed up by info from internet based on the user configuration which is written in preferences.
Is switching to a database solution more reliable or any other viable solution which will fix this "race condition"? (maybe forcing my own mechanism of synchronization, but as far as i've understood from docs, apply() is already synchronized, and the read/write should first go to RAM which should make it fast and i shouldnt be experiencing any problems like this since the user cant physically manage to delete a widget and place a new one faster then 2-3 seconds top!)
Try using the synchronized keyword in working with the SharedPreferences itself. For example, here is a method that could be used when setting an application String in the SharedPreferences of an Android app:
public synchronized static void setAppString(Context context, String pref,
String val) {
SharedPreferences sp = context.getSharedPreferences(
APP_PREFS_UNIQUE_ID, Context.MODE_PRIVATE);
Editor editor = sp.edit();
editor.putString(pref, val);
editor.commit();
}
For few/simple key-value pairs, you might not need the overhead of a database paradigm.

Migrate from getSharedPreferences(custom file) to getDefaultSharedPreferences()

When I originally wrote and published my app, I was using a custom written activity to handle application settings. I used custom file name to store shared preferfences, like this:
getSharedPreferences("custom_settings_file",MODE_PRIVATE);
But now I'm refactoring my app and I would like to implement PreferenceActivity or PreferenceFragment and an xml file with PreferenceScreen section. Every tutorial or example that I've seen is using
getDefaultSharedPreferences(context);
to retrieve shared preferences, because PreferenceActivity assumes default filename to store preferences and there's no way to tell it to use a different one(at least I couldn't find one after an hour of searching and reading documentation).
So now I have a problem. If I just simply use the new default file, existing users of my app will lose their settings when they update the app, because the new application will not know anything about "custom_settings_file". What would be the best way to move the data from an old file to a new one on app update?
Here are the possible options that I could come up with:
Extend Application class and implement a piece of code in onCreate() so that every time my app is launched, it would check for existence of "custom_settings_file" and move it's contents to the new one. But running a block of code on every app launch seems like wasting too much processing resources for an operation that only needs to run once.
Just notify the user that their old settings are gone. But obviously this is not acceptable.
Is there a better solution, than option 1? Perhaps someone has already faced a similar problem?
What is preventing you from doing number 1 only once?
Just add a "migration" boolean to the new sharedpreferences.
If you also load the xml preference file then you can try this:
PreferenceManager.setDefaultValues(context, YOUR_PREFERENCE_NAME, MODE_PRIVATE, R.xml.preference_file, false);
If not (you want to add each preference item dynamically in your code) then you can do like this:
PreferenceManager pm = getPreferenceManager();
pm.setSharedPreferencesMode(MODE_PRIVATE);
pm.setSharedPreferencesName(YOUR_PREFERENCE_NAME);
In case you still want to use the defaultSharedPreference and process the migration then ... I'm writing this and I see Nicklas's answer, so I'm done here.
Could you add value in your new SharedPreferences that records whether you are a new install or an upgrade. If you don't have the setting in your sharedpreferences, check to see if you have an old preferences file in the way you were before. Then convert those preferences to your new method, and set your private setting indicating that it's been upgraded. Then just set the new value indicating the new state and you won't need to check your old preferences any more.

SharedPreferences not being updated

I am having an odd issue in which the SharedPreferences are not being updated upon returning to an app. Here's the scenario:
I have two projects that use the same shared preferences. Project1 and Project2. They are separate but related apps. They are signed with the same key and use sharedUserId to share information.
Project1 opens Project2.
Project2 retrieves the SharedPreferences file and writes to it via this method:
Context prefsContext = c.createPackageContext(packageNameOfProject1, Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences prefs = prefsContext.getSharedPreferences(fileName, Context.MODE_PRIVATE);
SharedPreferences.editor editor = prefs.edit();
editor.putBool("bool1", value1);
editor.putBool("bool2", value2);
...
editor.putBool("boolN", valueN);
editor.apply();
Once that is done, I return to Project1 by calling finish().
Project1 then reads the data like so:
SharedPreferences prefs = getSharedPreferences(getPreferencesFileName(), Context.MODE_PRIVATE);
Boolean value1 = prefs.getBoolean(fileName, false);
Boolean value2 = prefs.getBoolean(fileName, false);
...
Boolean valueN = prefs.getBoolean(fileName, false);
Map<String, ?> mappings = prefs.getAll();
Set<String> keys = mappings.keySet();
for(String key : keys) {
log.d(TAG, "_____");
log.d(TAG, "Key = " + key);
log.d(TAG, "Value = " + mappings.get(key));
}
The problem is the values are not updated in Project1. I can tell based off the logs at the end that the file isn't even generating mappings. However, I can verify that the xml is being updated. If I force stop the app then restart it, all the mappings are there in Project1. All the values are correct. However, I need them updated when the user leaves Project2. I feel like there's something I'm missing here but can not spot it.
The only things I have been able to find on the subject is:
SharedPreferences.Editor not being updated after initial commit
SharedPreferences value is not updated
These don't help as I'm already doing that.
I have WRITE_EXTERNAL_STORAGE set in both manifests. The fileName is the same (else I wouldn't be able to read the file when I reenter the app).
EDIT:
I should note that I did try to do editor.commit() instead of editor.apply() as I thought I was facing a race condition. The problem still persisted. I'm thinking that for some reason, the old reference to the SharedPreference in Project1 is being used instead of a new one even though I'm lazy-loading it each time.
EDIT2:
Ok, to further test to see what id going on. I decided to try the opposite direction.
In Project1 I do:
Float testFloat (float) Math.random();
Log.d("TEST_FLOAT", "Project1: TEST_FLOAT = " + testFloat);
prefs.edit().putFloat("TEST_FLOAT", testFloat).commit();
In Project2 I do:
Log.d("TEST_FLOAT", "Project2: TEST_FLOAT = " + prefs.getFloat("TEST_FLOAT", 0.0f));
I then go back and forth between the two like so: Project1->Project2->Project1->Project2->Project1->Project2 and here is the logcat result:
Project1: TEST_FLOAT = 0.30341884
Project2: TEST_FLOAT = 0.30341884
Project1: TEST_FLOAT = 0.89398974
Project2: TEST_FLOAT = 0.30341884
Project1: TEST_FLOAT = 0.81929415
Project2: TEST_FLOAT = 0.30341884
In other words, it's reading and writing to the same file. However, it's keeping the mapping that it had when it was first opened it in the project. Even though I close the project, the mapping remains until the application is force stopped.
EDIT: I'm still getting upvotes on this answer even though it recommends a method that has since been deprecated. If you need consistent data through multi-process, then you need to use something other than SharedPreferences like a ContentProvider backed by a file system or database.
https://developer.android.com/reference/android/content/Context#MODE_MULTI_PROCESS
Final answer:
Replace
getSharedPreferences(fileName, Context.MODE_PRIVATE);
with
getSharedPreferences(fileName, Context.MODE_MULTI_PROCESS);
As per document:
Context.MODE_MULTI_PROCESS
SharedPreferences loading flag: when set, the file on disk will be
checked for modification even if the shared preferences instance is
already loaded in this process. This behavior is sometimes desired in
cases where the application has multiple processes, all writing to the
same SharedPreferences file. Generally there are better forms of
communication between processes, though.
This was the legacy (but undocumented) behavior in and before
Gingerbread (Android 2.3) and this flag is implied when targeting
such releases. For applications targeting SDK versions greater than
Android 2.3(Gingerbread), this flag must be explicitly set if desired.
I knew there was a simple oversight in this.
Try to call editor.commit(); instead of editor.apply();. Normally they should do the same, but I noticed there some weird behaviour sometimes.
From the SharedPreferences documentation the method "apply()" writes asynchronously (delayed) to the file and the method "commit()" writes the information synchronously (immediatly) to the file.
Also from the documentation, they say that you don't need to wary about the activity life cycle while using any of the above methods, as they ensure the "apply()" writes are completed before status changes, if they are running in the same system process.
However, as you are using two different projects, they run in two different processes and you can't be sure that "apply()" on project 2 will be concluded before the "onResume()" starts on project 1.
I suggest that you try "commit()" instead of "apply()" to force synchronous write. If this don't solve the issue, you can add a delay of a couple of seconds before reading the preferences in project 1, just to check if the issue is related to this delayed write.
--EDITED--
To debug the issue let's do the following:
1-In Eclipse Select/Add the view "File Explorer" and navigate to the directory:
/data/data/[your package name]/shared_prefs
your package name should be something like "com.myproject.shared"
2-Select the file with your saved preferences and press the button "download to PC".
3-Check if file contents match your expectations.
good luck.

Categories

Resources