Use saved Preference values   Part of Android Jetpack.

This document 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 supports 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 updates with a key-value pair of "notifications" : "true". The key used is the same as the key set for the Preference.

For more information about the SharedPreferences API, see Save key-value data.

For information about the different ways of storing data on Android, see Data and file storage overview.

PreferenceDataStore

Although 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 has separate settings, making SharedPreferences a less-than-ideal solution.

A PreferenceDataStore lets you use a custom storage backend to persist Preference values. For more information, see Use a custom datastore.

Read Preference values

To retrieve the SharedPreferences object that is being used, call PreferenceManager.getDefaultSharedPreferences(). Although this method works from anywhere in your application, we recommend that you split your app into layers. For more information, see Data layer.

For example, given an EditTextPreference with a key of "signature", as follows:

<EditTextPreference
        app:key="signature"
        app:title="Your signature"/>

You can retrieve the saved value for this Preference 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 following table shows how the two interfaces differ:

OnPreferenceChangeListener OnSharedPreferenceChangeListener
Set on a single Preference. Applies to all Preference objects.
Called when a Preference is about to change its saved value, even if the pending value is the same as the saved value. Called only when the value saved for a Preference changes.
Only called through the Preference library. A separate part of the application can change the saved value. Called whenever the saved value changes, even if it is from a separate part of the application.
Called before the pending value is saved. Called after the value is saved.
Called when using SharedPreferences or a PreferenceDataStore. Called only when using SharedPreferences.

Implement OnPreferenceChangeListener

Implementing an OnPreferenceChangeListener lets you listen for a pending change to the value of a Preference. Then, you can validate whether the change occurs. For example, the following code 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 follows:

Kotlin

preference.onPreferenceChangeListener = ...

Java

preference.setOnPreferenceChangeListener(...);

Implement OnSharedPreferenceChangeListener

When persisting Preference values using SharedPreferences, you can also use a SharedPreferences.OnSharedPreferenceChangeListener to listen for changes. This lets you listen for when the values saved by your Preference are changed, such as when syncing settings with a server. The following example shows how to listen for a change to the value of an EditTextPreference with a key of "name":

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, ""));
    }
}

Register the listener using registerOnSharedPreferenceChangedListener(), as follows:

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, register and unregister this listener in the onResume() and onPause() callbacks, as shown in the following example:

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);
}

Use a custom datastore

Although we recommend persisting Preference objects using SharedPreferences, you can also use a custom datastore. A custom datastore can be useful if your application persists values to a database or if values are device-specific, as shown in the following examples.

Implement the datastore

To implement a custom datastore, create a class that extends PreferenceDataStore. The following example creates a datastore 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.
    }
}

Run any time-consuming operations off the main thread to avoid blocking the user interface. Since it's possible for the Fragment or Activity containing the datastore to be destroyed while persisting a value, serialize the data so you don't lose any values changed by the user.

Enable the datastore

After you implement your datastore, set the new datastore in onCreatePreferences() so that Preference objects persist values with the datastore instead of using the default SharedPreferences. You can enable a datastore for each Preference or for the entire hierarchy.

To enable a custom datastore for a specific Preference, call setPreferenceDataStore() on the Preference, as shown in the following example:

Kotlin

val preference: Preference? = findPreference("key")
preference?.preferenceDataStore = dataStore

Java

Preference preference = findPreference("key");
if (preference != null) {
    preference.setPreferenceDataStore(dataStore);
}

To enable a custom datastore for an entire hierarchy, call setPreferenceDataStore() on the PreferenceManager:

Kotlin

val preferenceManager = preferenceManager
preferenceManager.preferenceDataStore = dataStore

Java

PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.setPreferenceDataStore(dataStore);

A datastore that is set for a specific Preference overrides any datastore that is set for the corresponding hierarchy. In most cases, you set a datastore for the whole hierarchy.