Cómo usar valores guardados   Part of Android Jetpack.

En este artículo, se describe cómo almacenar y utilizar los valores de Preference que guarda la Biblioteca de Preference.

Almacenamiento de datos de Preference

En esta sección, se describe cómo un elemento Preference puede recuperar datos.

SharedPreferences

De forma predeterminada, un Preference usa SharedPreferences para guardar valores. La API de SharedPreferences permite leer y escribir pares clave-valor simples desde un archivo que se guarda en todas las sesiones de la aplicación. La Biblioteca de Preference utiliza una instancia privada de SharedPreferences para que solo tu aplicación pueda acceder a ella.

A modo de ejemplo, asume el siguiente SwitchPreferenceCompat:

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

Cuando un usuario cambia este interruptor al estado On, se actualiza el archivo SharedPreferences con un par clave-valor de "notifications" : "true". Ten en cuenta que la clave utilizada es la misma que la establecida 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 formas de almacenar datos en Android, consulta Descripción general del almacenamiento de archivos y datos.

PreferenceDataStore

Si bien la Biblioteca de Preference recupera datos con SharedPreferences de forma predeterminada, SharedPreferences no siempre es la solución ideal. Por ejemplo, si tu aplicación requiere que un usuario inicie sesión, es posible que quieras mantener la configuración de la aplicación en la nube para que se refleje en otros dispositivos y plataformas De forma similar, si tu aplicación tiene opciones de configuración que son específicas del dispositivo, cada usuario tendrá configuraciones separadas, lo que hará que SharedPreferences sea una solución poco conveniente.

Un PreferenceDataStore te permite utilizar un backend de almacenamiento personalizado para mantener los valores de Preference. Para obtener más información, consulta Cómo usar un almacenamiento personalizado de datos.

Cómo leer valores de Preference

Para recuperar el objeto SharedPreferences que se esté usando, invoca a PreferenceManager.getDefaultSharedPreferences(). Este método funciona desde cualquier lugar de tu aplicación. Por ejemplo, si tenemos un EditTextPreference que tiene una clave de "firma":

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

El valor guardado de este Preference se puede recuperar globalmente 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 cambios en valores de Preference

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

La siguiente tabla muestra las diferencias entre ambas:

OnPreferenceChangeListener OnSharedPreferenceChangeListener
Se configura para cada elemento Preference. Se aplica a todos los elementos Preference.
Se invoca cuando un Preference está a punto de cambiar su valor guardado. Esto incluye si el valor pendiente es el mismo que el valor guardado actualmente. Solo se invoca si cambió el valor guardado de un Preference.
Solo se invoca a través de la Biblioteca de Preference. Una parte independiente de la aplicación podría cambiar el valor guardado. Se invoca siempre que cambie el valor guardado, incluso si es de una parte independiente de la aplicación.
Se invoca antes de guardar el valor pendiente. Se invoca después de que se guarda el valor.
Se invoca al usar SharedPreferences o PreferenceDataStore. Solo se invoca al usar SharedPreferences.

OnPreferenceChangeListener

Implementar un OnPreferenceChangeListener te permite detectar cuando el valor de un Preference está por cambiar. A partir de ahí, puedes validar si este cambio debería producirse. Por ejemplo, el siguiente código muestra cómo detectar un cambio en el valor de un EditTextPreference con una clave de "nombre":

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

Luego, debes configurar este receptor directamente con setOnPreferenceChangeListener(), como se muestra a continuación:

Kotlin

preference.onPreferenceChangeListener = ...

Java

preference.setOnPreferenceChangeListener(...);

OnSharedPreferenceChangeListener

Si recuperas valores de Preference usando SharedPreferences, también puedes usar SharedPreferences.OnSharedPreferenceChangeListener para detectar cambios. Esto te permite detectar cuando se cambian los valores que guarda tu elemento Preference, como cuando se sincroniza la configuración con un servidor. El siguiente ejemplo muestra cómo detectar cuando cambia el valor de un elemento EditTextPreference con una clave de "nombre" :

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

También debes registrar el receptor mediante registerOnSharedPreferenceChangedListener(), tal como se muestra a continuación:

Kotlin

preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(...)

Java

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

Kotlin

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

Java

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

Para una correcta gestión del ciclo de vida de Activity o Fragment, deberías registrar este receptor y darlo de baja en las devoluciones de llamada de onResume() y onPause() , como se muestra a continuación:

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

Cómo usar el almacenamiento personalizado de datos

Si bien se recomienda recuperar objetos Preference usando SharedPreferences, también puedes usar un almacenamiento personalizado de datos. Un almacenamiento de este tipo puede resultarte útil si tu aplicación recupera valores de una base de datos o si los valores son específicos de los dispositivos, por ejemplo.

Cómo implementar un almacenamiento de datos

Para implementar un almacenamiento personalizado de datos, primero debe crear una clase que amplíe PreferenceDataStore. El ejemplo que se incluye a continuación crea un almacenamiento de datos que controla valores de String:

Kotlin

class DataStore : PreferenceDataStore() {
    override fun putString(key: String, @Nullable value: String) {
        // Save the value somewhere
    }

    @Nullable
    override fun getString(key: String, @Nullable 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
    }
}

Asegúrate de ejecutar todas las operaciones que requieran mucho tiempo fuera del subproceso principal para evitar bloquear la interfaz de usuario. Dado que es posible destruir el objeto Fragment o Activity que contiene el almacenamiento de datos mientras se recupera un valor, debes serializar los datos para no perder ningún valor que modifique el usuario.

Cómo habilitar el almacenamiento de datos

Una vez que hayas implementado tu almacenamiento de datos, debes configurarlo en onCreatePreferences() para que los objetos Preference recuperen valores con el almacenamiento , en lugar de usar el elemento SharedPreferences predeterminado. Se puede habilitar un almacenamiento de datos para cada Preference o para la jerarquía completa.

A fin de habilitar un almacenamiento personalizado de datos para un objeto Preference específico, invoca a setPreferenceDataStore() en Preference, tal como se muestra en el siguiente ejemplo:

Kotlin

val preference = findPreference("key")
preference.preferenceDataStore = dataStore

Java

Preference preference = findPreference(“key”);
preference.setPreferenceDataStore(dataStore);

A fin de habilitar un almacenamiento para una jerarquía completa, invoca a setPreferenceDataStore() en PreferenceManager:

Kotlin

val preferenceManager = preferenceManager
preferenceManager.preferenceDataStore = dataStore

Java

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

Si se configura un almacenamiento de datos para un elemento Preference específico, se anulará cualquier almacenamiento que se establezca para la jerarquía correspondiente. En la mayoría de las cosas, deberías configurar un almacenamiento de datos para toda la jerarquía.