Cómo usar valores guardados   Parte de Android Jetpack

En este tema, se describe cómo almacenar y usar valores de Preference guardados en 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 valores. La API de SharedPreferences permite leer y escribir pares clave-valor simples de un archivo que se guarda en las sesiones de la aplicación. La biblioteca de Preference usa una instancia de SharedPreferences privada 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 establece este interruptor en el estado On, se actualiza el archivo SharedPreferences con un par clave-valor de "notifications" : "true". Recuerda que la clave que se usa es la misma que la clave configurada para el objeto 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 formas diferentes de almacenar datos en Android, consulta Descripción general del almacenamiento de datos y archivos.

PreferenceDataStore

Si bien 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 que un usuario acceda a su cuenta, se recomienda que conserves la configuración de la aplicación en la nube para que esa configuración se vea reflejada en otros dispositivos y plataformas. De la misma forma, si tu aplicación tiene opciones de configuración que son específicas del dispositivo, cada usuario del dispositivo debería tener configuraciones separadas, de modo que SharedPreferences deja de ser una solución tan ideal.

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

Cómo leer valores de Preference

Para recuperar el objeto SharedPreferences que se usa, llama a PreferenceManager.getDefaultSharedPreferences(). Este método funciona desde cualquier lugar de tu aplicación. Por ejemplo, a partir de un objeto EditTextPreference con una clave "signature":

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

El valor guardado para este objeto 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 los cambios en los valores de Preference

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

La siguiente tabla muestra las diferencias entre las dos interfaces:

OnPreferenceChangeListener OnSharedPreferenceChangeListener
Se configura para cada elemento Preference. Se aplica a todos los objetos Preference.
Se llama cuando un objeto Preference está a punto de cambiar el valor guardado. Esto incluye si el valor pendiente es igual al valor guardado actualmente. Se llama solamente cuando se modificó el valor guardado de un objeto Preference.
Solo se llama a través de la biblioteca de Preference. Una parte independiente de la aplicación podría cambiar el valor guardado. Se llama siempre que se modifica 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 ya se haya guardado el valor.
Se llama al usar SharedPreferences o PreferenceDataStore. Se llama solamente al usar SharedPreferences.

OnPreferenceChangeListener

Implementar un objeto OnPreferenceChangeListener te permite detectar el momento en que el valor de un objeto Preference está a punto de cambiar. A partir de allí, puedes validar si debería producirse ese cambio. Por ejemplo, el código que se incluye a continuación muestra cómo detectar un cambio en el valor de un objeto EditTextPreference con una clave "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, es necesario que configures este objeto de escucha directamente con setOnPreferenceChangeListener(), tal como se muestra a continuación:

Kotlin

preference.onPreferenceChangeListener = ...

Java

preference.setOnPreferenceChangeListener(...);

OnSharedPreferenceChangeListener

Al crear valores de Preference persistentes con SharedPreferences, también puedes usar un objeto SharedPreferences.OnSharedPreferenceChangeListener para detectar cambios. De esta forma, puedes detectar en qué momento se cambian los valores guardados por Preference, por ejemplo, cuando se sincroniza la configuración con un servidor. El siguiente ejemplo muestra cómo detectar el momento en el que cambia el valor de objeto EditTextPreference con una clave "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, ""));
    }
}

También debes registrar el objeto de escucha a través de registerOnSharedPreferenceChangedListener(), 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 administración adecuada del ciclo de vida de tu objeto Activity o Fragment, debes registrar y cancelar el registro de este objeto de escucha en las devoluciones de llamada 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 un almacén de datos personalizado

Si bien se recomienda crear objetos Preference persistentes con SharedPreferences, también puedes usar un almacén de datos personalizado. El almacén de datos personalizado puede ser útil, por ejemplo, si tu aplicación conserva valores en una base de datos o si los valores son específicos del dispositivo.

Cómo implementar el almacén de datos

Para implementar un almacén de datos personalizado, primero debes crear una clase que extienda el objeto PreferenceDataStore. El ejemplo de abajo crea un almacén de datos que controla 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
    }
}

No olvides ejecutar cualquier operación que requiera mucho tiempo fuera del subproceso principal para evitar bloquear la interfaz de usuario. Dado que se pueden destruir los objetos Fragment o Activity que contienen el almacén de datos mientras conservan un valor, debes serializar los datos para no perder ningún valor que el usuario haya modificado.

Cómo habilitar el almacén de datos

Después de haber implementado tu almacén de datos, debes configurar el nuevo almacén de datos en onCreatePreferences() para que los objetos Preference conserven valores con el almacén de datos en vez de usar el objeto SharedPreferences predeterminado. Se puede habilitar un almacén de datos para cada objeto Preference o para toda la jerarquía.

A fin de habilitar un almacén de datos personalizado para un objeto Preference específico, llama a setPreferenceDataStore() en el objeto Preference, tal 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);
}

A fin de habilitar un almacén de datos personalizado para una jerarquía entera, llama a setPreferenceDataStore() en el objeto PreferenceManager:

Kotlin

val preferenceManager = preferenceManager
preferenceManager.preferenceDataStore = dataStore

Java

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

Si se configura un almacén de datos para un objeto Preference específico, se anulará cualquier almacén de datos configurado para la jerarquía correspondiente. En la mayoría de los casos, debes configurar un almacén de datos para toda la jerarquía.