Cómo usar valores de Preference guardados Parte de Android Jetpack.

En este documento, se describe cómo almacenar y usar los valores Preference que guarda la biblioteca de Preference.

Almacenamiento de datos de Preference

En esta sección, se describe cómo un objeto Preference puede persistir datos.

SharedPreferences

De forma predeterminada, un objeto Preference usa SharedPreferences para guardar los valores. La API de SharedPreferences admite la lectura y escritura de pares clave-valor simples de un archivo que se guarda en las sesiones de la aplicación. La biblioteca de Preference usa una instancia privada de SharedPreferences para que solo tu aplicación pueda acceder a ella.

A modo de ejemplo, supongamos el siguiente objeto SwitchPreferenceCompat:

<SwitchPreferenceCompat
        app:key="notifications"
        app:title="Enable message notifications"/>

Cuando un usuario activa este interruptor, el archivo SharedPreferences se actualiza con un par clave-valor de "notifications" : "true". La clave que se usa es la misma que la clave configurada para Preference.

Para obtener más información sobre la API de SharedPreferences, consulta Cómo guardar datos de pares clave-valor.

Para obtener información sobre las diferentes maneras de almacenar datos en Android, consulta Descripción general del almacenamiento de datos y archivos.

PreferenceDataStore

Aunque la biblioteca de Preference conserva datos con SharedPreferences de forma predeterminada, SharedPreferences no siempre es una solución ideal. Por ejemplo, si tu aplicación requiere el acceso de un usuario, es posible que quieras conservar la configuración de la aplicación en la nube para que esta se refleje en otros dispositivos y plataformas. Del mismo modo, si tu aplicación tiene opciones de configuración específicas del dispositivo, cada usuario del dispositivo tiene configuraciones individuales, por lo que SharedPreferences no es una solución ideal.

Un objeto PreferenceDataStore te permite usar un backend de almacenamiento personalizado para conservar valores de Preference. Para obtener más información, consulta Usa un almacén de datos personalizado.

Cómo leer valores de Preference

Para recuperar el objeto SharedPreferences que se usa, llama a PreferenceManager.getDefaultSharedPreferences(). Si bien este método funciona desde cualquier parte de tu aplicación, te recomendamos que la dividas en capas. Para obtener más información, consulta Capa de datos.

Por ejemplo, a partir de un objeto EditTextPreference con una clave de "signature", se ve de la siguiente manera:

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

Puedes recuperar el valor guardado para este Preference a nivel global de la siguiente manera:

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

Cómo detectar los cambios en los valores de Preference

Para detectar cambios en los valores de Preference, puedes elegir entre dos interfaces:

En la siguiente tabla, se muestra cómo se diferencian las dos interfaces:

OnPreferenceChangeListener OnSharedPreferenceChangeListener
Se establece en un único Preference. Se aplica a todos los objetos Preference.
Se llama cuando un Preference está a punto de cambiar su valor guardado, incluso si el valor pendiente es el mismo que el guardado. Se llama solo cuando cambia el valor guardado para un Preference.
Solo se llama a través de la biblioteca Preference. Una parte independiente de la aplicación puede cambiar el valor guardado. Se llama cada vez que cambia el valor guardado, incluso si se trata de una parte independiente de la aplicación.
Se llama antes de que se guarde el valor pendiente. Se llama después de que se guarda el valor.
Se llama cuando se usa SharedPreferences o PreferenceDataStore. Se llama solamente al usar SharedPreferences.

Cómo implementar OnPreferenceChangeListener

Implementar un objeto OnPreferenceChangeListener te permite escuchar un cambio pendiente en el valor de un objeto Preference. Luego, puedes validar si el cambio ocurre. Por ejemplo, el siguiente código muestra cómo escuchar un cambio en el valor de un EditTextPreference con una clave de "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;
}

A continuación, debes configurar este objeto de escucha directamente con setOnPreferenceChangeListener() de la siguiente manera:

Kotlin

preference.onPreferenceChangeListener = ...

Java

preference.setOnPreferenceChangeListener(...);

Implementa OnSharedPreferenceChangeListener

Al crear valores de Preference persistentes con SharedPreferences, también puedes usar un objeto SharedPreferences.OnSharedPreferenceChangeListener para detectar cambios. Esto te permite escuchar cuando se cambian los valores guardados por tu Preference, como cuando se sincroniza la configuración con un servidor. En el siguiente ejemplo, se muestra cómo escuchar un cambio en el valor de un EditTextPreference con una clave de "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, ""));
    }
}

Registra el objeto de escucha con registerOnSharedPreferenceChangedListener() de la siguiente manera:

Kotlin

preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(...)

Java

getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(...);

Kotlin

    val listener: SharedPreferences.OnSharedPreferenceChangeListener =
            SharedPreferences.OnSharedPreferenceChangeListener {...}
    

Java

    SharedPreferences.OnSharedPreferenceChangeListener listener =
            new SharedPreferences.OnSharedPreferenceChangeListener() {...}
    

Para una administración adecuada del ciclo de vida en tu Activity o Fragment, registra y cancela el registro de este objeto de escucha en las devoluciones de llamada onResume() y onPause(), como se muestra en el siguiente ejemplo:

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

Usa un almacén de datos personalizado

Aunque recomendamos que persistas objetos Preference con SharedPreferences, también puedes usar un almacén de datos personalizado. Un almacén de datos personalizado puede ser útil si tu aplicación conserva valores en una base de datos o si los valores son específicos del dispositivo, como se muestra en los siguientes ejemplos.

Implementa el almacén de datos

Para implementar un almacén de datos personalizado, crea una clase que extienda PreferenceDataStore. En el siguiente ejemplo, se crea un almacén de datos que controla los valores de String:

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.
    }
}

Ejecuta las operaciones que requieran mucho tiempo fuera del subproceso principal para evitar bloquear la interfaz de usuario. Dado que es posible que los objetos Fragment o Activity que contienen el almacén de datos se destruyan mientras se conserva un valor, serializa los datos para no perder ningún valor que el usuario haya cambiado.

Habilita el almacén de datos

Después de implementar el almacén de datos, configúralo nuevo en onCreatePreferences() para que los objetos Preference conserven valores con el almacén de datos en lugar de usar el SharedPreferences predeterminado. Puedes habilitar un almacén de datos para cada Preference o para toda la jerarquía.

Si deseas habilitar un almacén de datos personalizado para un Preference específico, llama a setPreferenceDataStore() en el Preference, como se muestra en el siguiente ejemplo:

Kotlin

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

Java

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

Si deseas habilitar un almacén de datos personalizado para toda una jerarquía, llama a setPreferenceDataStore() en PreferenceManager:

Kotlin

val preferenceManager = preferenceManager
preferenceManager.preferenceDataStore = dataStore

Java

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

Un almacén de datos configurado para un Preference específico anula cualquier almacén de datos configurado para la jerarquía correspondiente. En la mayoría de los casos, configuras un almacén de datos para toda la jerarquía.