Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 314
DeeV Avatar asked Sep 27 '12 22:09

DeeV


People also ask

Are SharedPreferences persistent?

Shared preferences is an Android class that allows apps to store key-value pairs of primitive data types. Once saved, information in shared preferences will persist across sessions.

Is SharedPreferences persistent flutter?

SharedPreferences is used for storing data key-value pair in the Android and iOS. SharedPreferences in flutter uses NSUserDefaults on iOS and SharedPreferences on Android, providing a persistent store for simple data.

Does SharedPreferences persist after uninstall?

SharedPreferences is application specific, i.e. the data is lost on performing one of the following options: on uninstalling the application.

Is SQLite better than SharedPreferences?

With SQLite you use SQL language to create tables and then do insert, delete, update operations just like in any other database. But in case of shared preference you use just normal APIs provided by Android to write, read and update these values to a XML file.


3 Answers

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.

like image 191
DeeV Avatar answered Nov 03 '22 01:11

DeeV


Try to call editor.commit(); instead of editor.apply();. Normally they should do the same, but I noticed there some weird behaviour sometimes.

like image 44
Leandros Avatar answered Nov 02 '22 23:11

Leandros


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.

like image 26
Luis Avatar answered Nov 03 '22 00:11

Luis