Use saved values Part of Android Jetpack.
This topic describes how to store and use Preference
values that are saved by
the Preference Library.
Preference data storage
This section describes how a Preference
can persist data.
SharedPreferences
By default, a Preference
uses SharedPreferences
to save values. The SharedPreferences
API allows for reading and writing
simple key-value pairs from a file that is saved across application sessions.
The Preference Library uses a private SharedPreferences
instance so that only
your application can access it.
As an example, assume the following
SwitchPreferenceCompat
:
<SwitchPreferenceCompat app:key="notifications" app:title="Enable message notifications"/>
When a user toggles this switch to the On
state, the SharedPreferences
file
is updated with a key-value pair of "notifications" : "true"
. Note that the
key used is the same as the key set for the Preference
.
For more information on the SharedPreferences
API, see
Save key-value data.
For information on the different ways of storing data on Android, see Data and file storage overview.
PreferenceDataStore
While the Preference library persists data with SharedPreferences
by default,
SharedPreferences
aren’t always an ideal solution. For example, if your
application requires a user to sign in, you might want to persist application
settings in the cloud so that the settings are reflected across other devices
and platforms. Similarly, if your application has configuration options that are
device-specific, each user on the device would have separate settings, making
SharedPreferences
a less-than-ideal solution.
A PreferenceDataStore
enables you to use a custom storage backend to persist Preference
values. For
more information, see Using a custom data store.
Reading Preference values
To retrieve the SharedPreferences
object that is being used, call
PreferenceManager.getDefaultSharedPreferences()
.
This method works from anywhere in your application. For example, given an
EditTextPreference
with a key of "signature":
<EditTextPreference app:key="signature" app:title="Your signature"/>
The saved value for this Preference
can be retrieved globally as follows:
Kotlin
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this /* Activity context */) val name = sharedPreferences.getString("signature", "")
Java
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this /* Activity context */); String name = sharedPreferences.getString(“signature”, "");
Listen for changes to Preference values
To listen for changes to Preference
values, you can choose between two
interfaces:
The table below shows how the two interfaces differ:
OnPreferenceChangeListener | OnSharedPreferenceChangeListener |
---|---|
Set on a per-Preference basis | Applies to all Preferences |
Called when a Preference is about to change its saved value. This includes if the pending value is the same as the currently saved value. | Called only when the value saved for a Preference has changed. |
Only called through the Preference library. A separate part of the application could change the saved value. | Called whenever the value saved has changed, even if it is from a separate part of the application. |
Called before the pending value is saved. | Called after the value has already been saved. |
Called when using SharedPreferences or a PreferenceDataStore . |
Called only when using SharedPreferences . |
OnPreferenceChangeListener
Implementing an OnPreferenceChangeListener
allows you to listen for when the
value of a Preference
is about to change. From there, you can validate if this
change should occur. For example, the code below shows how to listen for a
change to the value of an EditTextPreference
with a key of "name":
Kotlin
override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { Log.e("preference", "Pending Preference value is: $newValue") return true }
Java
@Override public boolean onPreferenceChange(Preference preference, Object newValue) { Log.e("preference", "Pending Preference value is: " + newValue); return true; }
Next, you need to set this listener directly with
setOnPreferenceChangeListener()
,
as shown below:
Kotlin
preference.onPreferenceChangeListener = ...
Java
preference.setOnPreferenceChangeListener(...);
OnSharedPreferenceChangeListener
When persisting Preference
values using SharedPreferences
, you can also use
a SharedPreferences.OnSharedPreferenceChangeListener
to listen for changes.
This allows you to listen for when the values saved by your Preference
are
changed, such as when syncing settings with a server. The example below shows
how to listen for when the value of an EditTextPreference
with a key of "name"
changes:
Kotlin
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { if (key == "signature") { Log.i(TAG, "Preference value was updated to: " + sharedPreferences.getString(key, "")) } }
Java
@Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(“signature”)) { Log.i(TAG, “Preference value was updated to: “ + sharedPreferences.getString(key, "")); } }
You must also register the listener via
registerOnSharedPreferenceChangedListener()
,
as shown below:
Kotlin
preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(...)
Java
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(...);
Kotlin
val listener: SharedPreferences.OnSharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener {...}
Java
SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() {...}
For proper lifecycle management in your Activity
or Fragment
, you should
register and unregister this listener in the onResume()
and onPause()
callbacks, as shown below:
Kotlin
override fun onResume() { super.onResume() preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) } override fun onPause() { super.onPause() preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) }
Java
@Override public void onResume() { super.onResume(); getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); } @Override public void onPause() { super.onPause(); getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); }
Using a custom data store
While persisting Preference
objects using SharedPreferences
is recommended,
you can also use a custom data store. A custom data store can be useful if your
application persists values to a database or if values are device-specific, as
examples.
Implement the data store
To implement a custom data store, first create a class that extends
PreferenceDataStore
.
The example below creates a data store that handles String
values:
Kotlin
class DataStore : PreferenceDataStore() { override fun putString(key: String, value: String?) { // Save the value somewhere } override fun getString(key: String, defValue: String?): String? { // Retrieve the value } }
Java
public class DataStore extends PreferenceDataStore { @Override public void putString(String key, @Nullable String value) { // Save the value somewhere } @Override @Nullable public String getString(String key, @Nullable String defValue) { // Retrieve the value } }
Be sure to run any time-consuming operations off the main thread to avoid
blocking the user interface. Since it is possible for the Fragment
or
Activity
containing the data store to be destroyed while persisting a value,
you should serialize the data so you don’t lose any values changed by the user.
Enable the data store
After you have implemented your data store, you must set the new data store in
onCreatePreferences()
so that Preference
objects persist values with the
data store instead of using the default SharedPreferences
. A data store can be
enabled for each Preference
or for the entire hierarchy.
To enable a custom data store for a specific Preference
, call
setPreferenceDataStore()
on the Preference
, as shown in the example below:
Kotlin
val preference: Preference? = findPreference("key") preference?.preferenceDataStore = dataStore
Java
Preference preference = findPreference(“key”); if (preference != null) { preference.setPreferenceDataStore(dataStore); }
To enable a custom data store for an entire hierarchy, call
setPreferenceDataStore()
on the PreferenceManager
:
Kotlin
val preferenceManager = preferenceManager preferenceManager.preferenceDataStore = dataStore
Java
PreferenceManager preferenceManager = getPreferenceManager(); preferenceManager.setPreferenceDataStore(dataStore);
A data store that is set for a specific Preference
overrides any data store
that is set for the corresponding hierarchy. In most cases, you should set a
data store for the whole hierarchy.