Obsolete
Status Update
Comments
fl...@gmail.com <fl...@gmail.com> #2
[Comment deleted]
fl...@gmail.com <fl...@gmail.com> #3
I just ran into the same problem. I switched my app to run the service in a separate process and realized sharedPreferences was all broken.
Two things:
1) Are you using Editor.apply() or .commit() ? I was using .apply(). I started checking my preference file either after the activity or the service made changes to it and realized whenever one would make a change, it would create a new file with only the newly changed value. I.E., a value written from the activity would be erased when a new value was written/changed from the service and vice versa. I switched to .commit() everywhere and this is no longer the case! From the documentation: "Note that when two editors are modifying preferences at the same time, the last one to call apply wins.
Unlike commit, which writes its preferences out to persistent storage synchronously, apply commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures."
2) SharedPreferencesListener doesn't appear to work across processes even after switching to .commit(). You'll have to use Messenger Handlers or Broadcast Intents to notify of a change. When you look at the documentation for the SharedPreferences class it even says "Note: currently this class does not support use across multiple processes. This will be added later."http://developer.android.com/reference/android/content/SharedPreferences.html
In that respect we're lucky we even have the MODE_MULTI_PROCESS flag working to read/write from the same SharedPreferences across different processes.
Two things:
1) Are you using Editor.apply() or .commit() ? I was using .apply(). I started checking my preference file either after the activity or the service made changes to it and realized whenever one would make a change, it would create a new file with only the newly changed value. I.E., a value written from the activity would be erased when a new value was written/changed from the service and vice versa. I switched to .commit() everywhere and this is no longer the case! From the documentation: "Note that when two editors are modifying preferences at the same time, the last one to call apply wins.
Unlike commit, which writes its preferences out to persistent storage synchronously, apply commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures."
2) SharedPreferencesListener doesn't appear to work across processes even after switching to .commit(). You'll have to use Messenger Handlers or Broadcast Intents to notify of a change. When you look at the documentation for the SharedPreferences class it even says "Note: currently this class does not support use across multiple processes. This will be added later."
In that respect we're lucky we even have the MODE_MULTI_PROCESS flag working to read/write from the same SharedPreferences across different processes.
ga...@gmail.com <ga...@gmail.com> #4
No, I've used only "commit", and as I said this might work ok, but once in few days of regular usage of my 2-processes app and the prefs would get reset.
So I wrote the above loop to check it, and it shows the problem appears within a minute or two of extensive writing and reading.
Can you try running a loop of reads and writes of a random number from your service and your main app, and see if you can recreate my findings?
So I wrote the above loop to check it, and it shows the problem appears within a minute or two of extensive writing and reading.
Can you try running a loop of reads and writes of a random number from your service and your main app, and see if you can recreate my findings?
na...@gmail.com <na...@gmail.com> #5
I have a same problem and I use sync adapter too.
This is a very critical issue.
This is a very critical issue.
fl...@gmail.com <fl...@gmail.com> #6
[Comment deleted]
fl...@gmail.com <fl...@gmail.com> #7
Did you find a work around for this? I started running into problems when the processes tried to read/write at the same time. The sharedPrefs file would sometimes even get deleted altogether!
Check out the last comments on the last answer here:
http://stackoverflow.com/questions/9279532/android-sharedpreferences-concurrency
Check out the last comments on the last answer here:
ba...@gmail.com <ba...@gmail.com> #8
[Comment deleted]
da...@spotify.com <da...@spotify.com> #9
The reason the file is deleted is this:
commit() will create a backup file while executing SharedPrefs.writeToFile(). If the master file is successfully written, the backup file will be deleted. However, if Process2 runs SharedPrefs.loadFromDiskLocked() (e.g. because you open the prefs multiprocess) it will check if there is a backup file. If it exists, the master file will be deleted and the backup file will be renamed to the master file. If you're really unlucky, Process2 sees the backup file and deletes master, but Process1's writeToFile will delete it before it has been renamed.
commit() will create a backup file while executing SharedPrefs.writeToFile(). If the master file is successfully written, the backup file will be deleted. However, if Process2 runs SharedPrefs.loadFromDiskLocked() (e.g. because you open the prefs multiprocess) it will check if there is a backup file. If it exists, the master file will be deleted and the backup file will be renamed to the master file. If you're really unlucky, Process2 sees the backup file and deletes master, but Process1's writeToFile will delete it before it has been renamed.
en...@google.com <en...@google.com>
te...@gmail.com <te...@gmail.com> #10
Can we get an explanation as to why this has been closed as obsolete?
va...@gmail.com <va...@gmail.com> #11
Why is this obsolete ?
It still happens in 4.4.2 if a preference is set using a EditTextPreference. If the property is ready from a SyncAdapter the old value (before changing in edit text preference) will still be used.
The default shared preferences where accessed like this
context.getSharedPreferences(application.getPackageName() + "_preferences", Context.MODE_MULTI_PROCESS);
from the sync adapter in order to get the default shared preferences with MODE_MULTI_PROCESS.
It still happens in 4.4.2 if a preference is set using a EditTextPreference. If the property is ready from a SyncAdapter the old value (before changing in edit text preference) will still be used.
The default shared preferences where accessed like this
context.getSharedPreferences(application.getPackageName() + "_preferences", Context.MODE_MULTI_PROCESS);
from the sync adapter in order to get the default shared preferences with MODE_MULTI_PROCESS.
r4...@gmail.com <r4...@gmail.com> #12
[Comment deleted]
r4...@gmail.com <r4...@gmail.com> #13
I was seeing what appeared to be this issue (MODE_PRIVATE) using "build-tools 21.1.2".
Upgrading to "build-tools 22.0.1" appears to have resolved the issue.
Upgrading to "build-tools 22.0.1" appears to have resolved the issue.
pa...@gmail.com <pa...@gmail.com> #14
[Comment deleted]
pa...@gmail.com <pa...@gmail.com> #15
I wrote a library to come around this problem: https://github.com/grandcentrix/tray
It uses a internal ContentProvider which stores the data and I never had problem when saving something in my SyncAdapters since.
It uses a internal ContentProvider which stores the data and I never had problem when saving something in my SyncAdapters since.
Description
SETUP:
SyncAdapter runs on its own process.
All other code runs on the default application process.
There's a wrapper class around SharedPreferences that has set/get methods for prefs in the prefs file.
I wrote a small test method that loops forever setting and getting values (random) to/from a single pref in the prefs file.
Devices tested: Nexus 5, Nexus 4, Galaxy S3.
Expected behavior:
Value that was 'set' to the pref on either process would then be returned in the next 'get' calls on either process.
FIRST ISSUE:
Initially I had a static SharedPreferences object in the wrapper class that was init once via:
sPrefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_MULTI_PROCESS | Context.MODE_PRIVATE);
Observed behavior:
Each process got the value that it set, not the latest one set.
i.e.
...
getTempString: "481" (process 17079) (time 1393930179666)
setTempString: "602" (process 16847)
getTempString: "481" (process 17079) (time 1393930179767)
getTempString: "602" (process 16847) (time 1393930179792)
getTempString: "481" (process 17079) (time 1393930179867)
...
This is easily reproducible, on all our test devices (Nexus 5, Nexus 4, Galaxy S3)
SECOND ISSUE:
After getting a suggestion on StackOverflow to not keep a static SharedPreferences object, I changed the wrapper class to init the SharedPreferences on each get/set.
That initially seemed to work, producing this log:
setTempString: "977" (process 15679)
getTempString: "977" (process 15679) (time 1393929223589)
getTempString: "977" (process 15415) (time 1393929223609)
getTempString: "977" (process 15679) (time 1393929223689)
getTempString: "977" (process 15415) (time 1393929223709)
However, after some short period of time (~1 min), the following weirdness happens:
...
getTempString: 332 (15679) (1393929288410)
getTempString: 332 (15415) (1393929288506)
getTempString: 332 (15679) (1393929288511)
setTempString: 392 (15415) <= this set was somehow 'ignored'
getTempString: 332 (15679) (1393929288618)
getTempString: 332 (15679) (1393929288718)
getTempString: 332 (15415) (1393929288720)
...
getTempString: 332 (15415) (1393929291536)
setTempString: 846 (15679) <= the next 'set' attempt after an 'ignored' set
getTempString: null (15415) (1393929291642) <= from this line forward, not only the current key was deleted, ALL THE KEYS ON THE FILE GOT DELETED
P.S. I've tried without Context.MODE_PRIVATE flag as well, no difference.