Accessing Android Shared Preferences Across Multiple Processes
February 2, 2016Accessing Android Shared Preferences Across Multiple Processes
Shared preferences are the primary way for an app to persist small bits of information such as user-selected settings. You can persist simple Java primitives like int
s, boolean
s and float
s or complex objects like String
s, Parcelable
s, and Serializable
s. Many developers are introduced to shared preferences with a simple example showing how to store and retrieve values through the default shared preferences.
// persist the preference
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
.putBoolean("PREF_USER_LIKES_COOKIES", true)
.commit();
// retrieve the preference
boolean userLikesCookies =
PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean("PREF_USER_LIKES_COOKIES", false);
Pretty simple, right?
Accessing a Shared Preference From Another Process
Now let’s say that we want to edit this preference in one process and access it from another process.
Let’s set up a LocaleChangeReceiver:
<receiver
android:name=".LocaleChangeReceiver">
<intent-filter>
<action android:name="android.intent.action.LOCALE_CHANGED"/>
</intent-filter>
</receiver>
public class LocaleChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
.putBoolean("PREF_USER_LIKES_COOKIES", new Random().nextBoolean())
.commit();
}
}
This receiver runs whenever the device’s locale or language is changed but it runs in a separate process from our app’s main process. When we edit and commit the shared preference in LocaleChangeReceiver’s process, the change may or may not have persisted by the time we attempt to read it in the main process. Each process has their own instance of the app’s shared preferences, and when one process edits a shared preference, the changes may not be reflected in another process’s instance for an indeterminate amount of time.
MODE_MULTI_PROCESS
Up to and including Android API level 9 (OS version 2.3), shared preference instances between processes were checked to ensure that the latest changes were reflected amongst all processes. However after API level 9, the MODE_MULTI_PROCESS flag must be set when accessing shared preferences.
In order to use this mode flag you will have to read/write your shared preferences using Context.getSharedPreferences()
where you select a file name and various mode flags.
context.getSharedPreferences(
"shared pref file name",
Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS
);
When you access default shared preferences with
PreferenceManager.getDefaultSharedPreferences(context)
you’re ultimately calling this under the hood:
context.getSharedPreferences(
context.getPackageName() + "_preferences",
Context.MODE_PRIVATE
);
This means that the file name and mode of your existing shared preferences are already set in stone and are unchangeable. To use Context.MODE_MULTI_PROCESS
you will have to migrate your app’s existing shared preferences to a new shared preferences file.
public static void migrateSharedPreferences(Context context) {
// retrieve the preference from the default shared preferences...
boolean oldDefaultSharedPrefUserLikesCookies =
PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean("PREF_USER_LIKES_COOKIES", false);
// ...and set it in a new shared preferences file that uses Context.MODE_MULTI_PROCESS
context.getSharedPreferences(
"{user prefs file name}",
Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS
)
.edit()
.putBoolean("PREF_USER_LIKES_COOKIES", oldDefaultSharedPrefUserLikesCookies)
.commit();
}
Now you can access your migrated shared preferences.
boolean userLikesCookies =
context.getSharedPreferences(
"{user prefs file name}",
Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS
).getBoolean("PREF_USER_LIKES_COOKIES", false);
Once you’ve migrated your default shared preferences to a non-default shared preferences file that uses Context.MODE_MULTI_PROCESS
, your shared preference instances amongst processes are written and read immediately as you would expect.
API Level 23 (6.0) Deprecation
However, as of API Level 23 (OS version 6.0), Context.MODE_MULTI_PROCESS
is deprecated as it has been deemed unreliable in some versions of Android. The documentation recommends that you instead use a ContentProvider (i.e. the system’s underlying SQLite database) to manage shared preferences that need to be shared amongst multiple processes. Again, if you were previously using Context.MODE_MULTI_PROCESS
this means you will need to migrate your existing shared preferences over to being managed by a ContentProvider
.
Setting up a ContentProvider
and its accompanying boilerplate code feels like overkill just to store your simple shared preferences. You don’t have to do it for all your shared preferences but you may not be able to predict which ones will need to be accessed from multiple processes in the future.
The Solution
An elegant solution to this dilemma is Tray, an Android library that uses a ContentProvider
underneath its hood to allow you to read and write shared preferences with an API similar to the Android SharedPreference
API. It even provides a mechanism for migrating over existing preferences to be managed by the library.
Moving forward, it seems prudent to manage all shared preferences by either this library or manually through a ContentProvider
, as one can not predict how shared preferences will need to be accessed in the future, and we can avoid having to migrate old shared preferences. We welcome other developers who have come across this problem to share their experiences and thoughts on the matter. What other methods have you found to be useful for inter-process sharing of shared preferences?
Looking for more like this?
Sign up for our monthly newsletter to receive helpful articles, case studies, and stories from our team.
2022 Best and Brightest Winners in West Michigan
May 2, 2022The Best and Brightest Companies to Work For® competition identifies and honors organizations that display a commitment to excellence in operations and employee enrichment that lead to increased productivity and financial performance!
Read moreDelivering software value faster: How to track ROI from day one
October 24, 2024Do you feel under pressure to innovate quickly, make smart investments, and prove the value of your digital products? How do you measure the return on investment (ROI) from a software project, especially when you can’t afford to wait six months to a year to verify measurable results?
Read moreHow to Prepare for our Associate Software Developer Position
June 30, 2023Tips for applying to MichiganLab's Associate Software Developer program
Read more