2

I'm having troubles trying to get SharedPreferences working.

this is the code:

/**
 * Sets the software in synchronizing status.
 * @param synchronizing Boolean
 */
public void setSynchronizing(boolean synchronizing) {
    if(D) Log.d(TAG, "Called: setSynchronizing("+synchronizing+")");
    SharedPreferences preferences = mContext.getSharedPreferences(SharedPrefsConstants.PREFERENCES, 0);
    SharedPreferences.Editor editor = preferences.edit();
    editor.putBoolean(SharedPrefsConstants.SYNCHRONIZING, synchronizing);
    boolean result = editor.commit();
    if(!result)
        Log.w(TAG, "Cannot store the preference.");
    if(!synchronizing)
        BroadcastUtils.stopSynchronizing(mContext);
}

/**
 * Returns whether the software is synchronizing.
 * @return True if synchronization is happening.
 */
public boolean isSynchronizing() {
    SharedPreferences preferences = mContext.getSharedPreferences(SharedPrefsConstants.PREFERENCES, 0);
    boolean synchronizing = preferences.getBoolean(SharedPrefsConstants.SYNCHRONIZING, false);
    if(D) Log.d(TAG, "Called: isSynchronizing Returning: "+synchronizing);
    return synchronizing;
}

and this is the logcat output, please note that i'm using two separate processes in my application, i'll call them app and app:bg:

**app** D/StorageManager﹕ Called: setSynchronizing(true)
**app** D/StorageManager﹕ Called: setSynchronizing(true)
**app** D/StorageManager﹕ Called: isSynchronizing Returning: true
**app** D/StorageManager﹕ Called: isSynchronizing Returning: true
**app:bg** D/StorageManager﹕ Called: setSynchronizing(false)
**app** D/StorageManager﹕ Called: isSynchronizing Returning: true

StorageManager is a singleton instance, but there are two of those instances, one for each process.

Even if setSynchronizing(false) is being called from background thread, the physical preference file is changed correctly, but in the foreground thread it is still true.

You can see that isSynchronizing method is returning true after setSynchronizing sets that variable to false. Question is: why do this happens? This is the first time i use SharedPreferences in this software, so it cannot be set anywhere else.

This is the preference file stored inside the phone, when isSynchronizing is still returning TRUE:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<boolean name="synchronizing" value="false" />
</map>

The only thing that i can think of is that SharedPreferences holds some sort of cache in memory, if you can confirm this there is some way to force the update of a SharedPreference?

I must also say that a considerable amount of time is passing between the variable being set to false and any other subsequent call to isSynchronizing from the foreground thread.

Luca Vitucci
  • 3,674
  • 4
  • 36
  • 60
  • 1
    How is what possible? – dymmeh Oct 04 '13 at 15:07
  • Sorry for that, edited question. – Luca Vitucci Oct 04 '13 at 15:11
  • Have you tried uninstalling the app, and installing it again? – Emmanuel Oct 04 '13 at 15:39
  • I'm uninstalling the app each time i deploy it. – Luca Vitucci Oct 04 '13 at 15:42
  • You're calling setSynchronizing(true); before retrieving the value. Why would you expect the result to be false when you set it to true first? – dymmeh Oct 04 '13 at 15:45
  • This is all i can think of: I'm setting Synchronizing to true in process A, then i'm reading it from process A, obviously it's true. I'm then setting it to false from process B and file updates correctly, but when i read it from process A, it's still set to true. Doesn't it sounds like a cache? Can i force android to re-read the preference from file? – Luca Vitucci Oct 04 '13 at 15:47
  • I'm setting it to false again after setting it true... – Luca Vitucci Oct 04 '13 at 15:49
  • Try this: 1) Remove multiple instances of `SharedPreferences preferences = ...` 2) Add `private SharedPreferences mSharedPreferences;` 3) Make consecutive calls only through the `mSharedPreferences` 4) see what happens :-) – ozbek Oct 04 '13 at 16:04

1 Answers1

1

I found a solution.

It seems like SharedPreferences is not a Process-Safe class, it can work with multiple processes if you set a flag when calling getSharedPreferences:

MODE_MULTI_PROCESS

This solves the problem.

Luca Vitucci
  • 3,674
  • 4
  • 36
  • 60
  • 1
    The bug in 2.3 block the multi process communication: oshttp://stackoverflow.com/questions/12125214/shared-preferences-between-two-processes-of-the-same-application – Bytecode Oct 14 '13 at 08:08
  • 1
    I'm pretty sure `MODE_MULTI_PROCESS` just causes `getSharedPreferences()` to reload the preferences from the file if necessary, but only *once*. It doesn't actually provide multi-process safety. There are [known issues](https://code.google.com/p/android/issues/detail?id=66625) with this, even with the flag, and the source code (`SharedPreferencesImpl`) doesn't look multi-process safe at all. – Sam Jul 09 '15 at 13:16
  • 1
    This flag is now (SDK 23) deprecated. You should use a ContentProvider instead: https://developer.android.com/reference/android/content/Context.html#MODE_MULTI_PROCESS – Mark Jun 21 '16 at 12:19