Usar valores de preferência salvos Parte do Android Jetpack

Este documento descreve como armazenar e usar valores de Preference que são salvos pela biblioteca Preference.

Armazenamento de dados de preferências

Esta seção descreve como uma Preference pode manter dados.

SharedPreferences

Por padrão, um Preference usa SharedPreferences para salvar valores. A API SharedPreferences oferece suporte à leitura e gravação de pares de chave-valor simples de um arquivo salvo nas sessões do aplicativo. A biblioteca Preference usa uma instância particular de SharedPreferences para que somente seu aplicativo possa acessá-la.

Como exemplo, considere o seguinte SwitchPreferenceCompat:

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

Quando um usuário muda essa chave para o estado "ativado", o arquivo SharedPreferences é atualizado com um par de chave-valor de "notifications" : "true". A chave usada é a mesma definida para o Preference.

Para mais informações sobre a API SharedPreferences, consulte Salvar dados de chave-valor.

Para ver informações sobre as diferentes maneiras de armazenar dados no Android, consulte Visão geral do armazenamento de dados e arquivos.

PreferenceDataStore

Embora a biblioteca Preference mantenha os dados com SharedPreferences por padrão, SharedPreferences nem sempre é a solução ideal. Por exemplo, se o aplicativo exige que o usuário faça login, mantenha as configurações do aplicativo na nuvem para que elas sejam refletidas em outros dispositivos e plataformas. Da mesma forma, se o aplicativo tiver opções de configuração específicas do dispositivo, cada usuário no dispositivo terá configurações separadas, tornando SharedPreferences uma solução não ideal.

Um PreferenceDataStore permite usar um back-end de armazenamento personalizado para manter os valores de Preference. Para mais informações, consulte Usar um armazenamento de dados personalizado.

Ler valores de preferência

Para recuperar o objeto SharedPreferences que está sendo usado, chame PreferenceManager.getDefaultSharedPreferences(). Embora esse método funcione em qualquer lugar do seu app, recomendamos dividir o app em camadas. Para mais informações, consulte Camada de dados.

Por exemplo, considerando um EditTextPreference com uma chave de "signature", desta maneira:

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

Você pode recuperar o valor salvo para esse Preference globalmente, da seguinte maneira:

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

Detectar as mudanças nos valores de preferência

Para detectar mudanças em valores de Preference, você pode escolher entre duas interfaces:

A tabela a seguir mostra as diferenças entre as duas interfaces:

OnPreferenceChangeListener OnSharedPreferenceChangeListener
Definido em um único Preference. Aplica-se a todos os objetos Preference.
Chamado quando um Preference está prestes a mudar o valor salvo, mesmo que o valor pendente seja igual ao valor salvo. Chamado somente quando o valor salvo para uma Preference muda.
Chamada somente pela biblioteca Preference. Uma parte separada do aplicativo pode mudar o valor salvo. Chamado sempre que o valor salvo muda, mesmo que seja de uma parte separada do app.
Chamada antes de o valor pendente ser salvo. Chamado depois que o valor é salvo.
Chamado ao usar SharedPreferences ou PreferenceDataStore. Chamada somente ao usar SharedPreferences.

Implementar OnPreferenceChangeListener

A implementação de um OnPreferenceChangeListener permite detectar uma mudança pendente no valor de um Preference. Em seguida, você pode validar se a mudança ocorre. Por exemplo, o código a seguir mostra como detectar uma mudança no valor de EditTextPreference com uma chave 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;
}

Em seguida, você precisa definir esse listener diretamente com setOnPreferenceChangeListener() da seguinte maneira:

Kotlin

preference.onPreferenceChangeListener = ...

Java

preference.setOnPreferenceChangeListener(...);

Implementar OnSharedPreferenceChangeListener

Ao manter valores de Preference usando SharedPreferences, você também pode usar um SharedPreferences.OnSharedPreferenceChangeListener para detectar mudanças. Isso permite que você detecte quando os valores salvos pelo Preference mudam, como ao sincronizar configurações com um servidor. O exemplo abaixo mostra como detectar uma mudança no valor de EditTextPreference com uma chave 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, ""));
    }
}

Registre o listener usando registerOnSharedPreferenceChangedListener(), da seguinte maneira:

Kotlin

preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(...)

Java

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

Kotlin

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

Java

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

Para um gerenciamento adequado do ciclo de vida em Activity ou Fragment, registre e cancele o registro desse listener nos callbacks onResume() e onPause(), conforme mostrado neste exemplo:

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

Usar um repositório de dados personalizado

Embora seja recomendável persistir objetos Preference usando SharedPreferences, também é possível usar um repositório de dados personalizado. Um armazenamento de dados personalizado pode ser útil se o aplicativo persistir valores em um banco de dados ou se os valores forem específicos do dispositivo, como mostrado nos exemplos a seguir.

Implementar o repositório de dados

Para implementar um repositório de dados personalizado, crie uma classe que estenda PreferenceDataStore. O exemplo abaixo cria um repositório de dados que processa 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.
    }
}

Execute qualquer operação demorada fora da linha de execução principal para evitar o bloqueio da interface do usuário. Como é possível que o Fragment ou o Activity que contém o repositório de dados sejam destruídos enquanto um valor é mantido, serialize os dados para que você não perca nenhum valor alterado pelo usuário.

Ativar o repositório de dados

Depois de implementar seu repositório de dados, defina o novo repositório em onCreatePreferences() para que objetos Preference mantenham valores com o repositório de dados em vez de usar o SharedPreferences padrão. É possível ativar um repositório de dados para cada Preference ou para toda a hierarquia.

Para ativar um armazenamento de dados personalizado para um Preference específico, chame setPreferenceDataStore() no Preference, conforme mostrado no exemplo a seguir.

Kotlin

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

Java

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

Para ativar um repositório de dados personalizado para toda a hierarquia, chame setPreferenceDataStore() em PreferenceManager:

Kotlin

val preferenceManager = preferenceManager
preferenceManager.preferenceDataStore = dataStore

Java

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

Um armazenamento de dados definido para um Preference específico substitui qualquer repositório de dados definido para a hierarquia correspondente. Na maioria dos casos, você define um armazenamento de dados para toda a hierarquia.