Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MODE_MULTI_PROCESS for SharedPreferences isn't working

I have a SyncAdapter running on its own process separately from the main app process.

I'm using a static wrapper class around my SharedPreferences that creates a static object on process load (Application's onCreate) like so:

myPrefs = context.getSharedPreferences(MY_FILE_NAME, Context.MODE_MULTI_PROCESS | Context.MODE_PRIVATE); 

The wrapper has get and set methods, like so:

public static String getSomeString() {     return myPrefs.getString(SOME_KEY, null); }  public static void setSomeString(String str) {     myPrefs.edit().putString(SOME_KEY, str).commit(); } 

Both SyncAdapter and app uses this wrapper class to edit and get from the prefs, this works sometimes but a lot of times I see the SyncAdapter getting old/missing prefs on accesses to the prefs, while the main app sees the recent changes properly.

According to the docs I think the MODE_MULTI_PROCESS flag should work as I expect it to, allowing both processes to see latest changes, but it doesn't work.

Update:

Per x90's suggestion, I've tried refraining from using a static SharedPreferences object and instead calling getSharedPreferences on each get/set method. This caused a new issue, where the prefs file gets deleted (!!!) on multi-process simultaneous access. i.e. I see in the logcat:

(process 1): getName => "Name" (process 2): getName => null (process 1): getName => null 

and from that point all the prefs saved on the SharedPreferences object were deleted.

This is probably a result of another warning I see in the log:

W/FileUtils(21552): Failed to chmod(/data/data/com.my_company/shared_prefs/prefs_filename.xml): libcore.io.ErrnoException: chmod failed: ENOENT (No such file or directory) 

P.S this is not a deterministic issue, I saw the above logs after a crash happened, but couldn't recreate yet on the same device, and until now it didn't seem to happen on other devices.

ANOTHER UPDATE:

I've filed a bug report on this, after writing a small testing method to confirm this is indeed an Android issue, star it at https://code.google.com/p/android/issues/detail?id=66625

like image 345
marmor Avatar asked Mar 02 '14 15:03

marmor


People also ask

Can I save array list in SharedPreferences?

You can save String and custom array list using Gson library. =>First you need to create function to save array list to SharedPreferences. public void saveListInLocal(ArrayList<String> list, String key) { SharedPreferences prefs = getSharedPreferences("AppName", Context. MODE_PRIVATE); SharedPreferences.

Is SQLite better than SharedPreferences?

To give an example, SharedPreferences are useful for storing user preferences, where there are just a handful of variables that need storing. SQLite on the other hand would be better for storing data where there is a large set of items, such as song titles in a music library which need to be searched through.

How can I check my data usage on SharedPreferences?

Click on the package name for your application. After that click on the shared_prefs folder and inside that open the shared_prefs. xml file. Now you will get to see the data which we stored in our shared preferences from our application.


2 Answers

I gave a very quick look at Google's code and apparently Context.MODE_MULTI_PROCESS is not an actual way to ensure process-safety of SharedPreferences.

SharedPreferences itself is not process-safe. (That's probably why SharedPreferences documentation says "currently this class does not support use across multiple processes. This will be added later.")

MODE_MULTI_PROCESS just works in conjunction with every Context.getSharedPreferences(String name, int mode) call: when you retrieve an instance of SharedPreferences specifying the MODE_MULTI_PROCESS flag android will reload the preferences file to be up to date with any (eventual) concurrent modification that occurred to it. If you then keep that instance as a class (static or not) member, the preference file won't be reloaded again.

Using Context.getSharedPreferences(...) every time you want to write or read into preferences is not process-safe either, but I guess it's probably the closest that you can get to it at the moment.

If you don't actually need to read the same preference from the different processes, then a workaround could be to use different preferences files for the different processes.

like image 53
Soloist Avatar answered Sep 28 '22 09:09

Soloist


Had exactly the same problem and my solution was to write a ContentProvider based replacement for the SharedPreferences. It works 100% multiprocess.

I made it a library for all of us. Here is the result: https://github.com/grandcentrix/tray

like image 33
passsy Avatar answered Sep 28 '22 08:09

passsy