使用保存的偏好设置值 Android Jetpack 的一部分。

本文档介绍了如何存储和使用由 Preference 库保存的 Preference 值。

Preference 数据存储

本部分介绍了 Preference 会如何保留数据。

SharedPreferences

默认情况下,Preference 使用 SharedPreferences 保存值。SharedPreferences API 支持从跨应用会话保存的文件读取和写入简单的键值对。Preference 库使用不公开的 SharedPreferences 实例,因此只有您的应用可以访问该实例。

举例来说,我们假设存在以下 SwitchPreferenceCompat

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

当用户将此开关切换到“开启”状态时,SharedPreferences 文件会使用 "notifications" : "true" 键值对进行更新。所用键与为 Preference 设置的键相同。

如需详细了解 SharedPreferences API,请参阅保存键值对数据

如需了解在 Android 上存储数据的不同方法,请参阅数据和文件存储概览

PreferenceDataStore

虽然 Preference 库默认通过 SharedPreferences 保留数据,但 SharedPreferences 并不总是理想的解决方案。例如,如果您的应用要求用户登录,建议您在云端保留应用设置,以便在其他设备和平台上体现这些设置。同样,如果您的应用具有特定于设备的配置选项,则设备上的每个用户都有单独的设置,这样一来,SharedPreferences 就不是理想的解决方案。

借助 PreferenceDataStore,您可以使用自定义存储后端来保留 Preference 值。如需了解详情,请参阅使用自定义数据存储区

读取偏好设置值

如要检索正在使用的 SharedPreferences 对象,请调用 PreferenceManager.getDefaultSharedPreferences()。虽然这种方法适用于应用的任何位置,但我们建议您将应用拆分为多层。如需了解详情,请参阅数据层

例如,假设有一个 EditTextPreference 的键为 "signature",如下所示:

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

您可以全局检索此 Preference 的已保存值,如下所示:

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

监听 Preference 值的更改

如要监听 Preference 值的更改,您可以在以下两个接口中选择一个:

下表显示了这两个接口的区别:

OnPreferenceChangeListener OnSharedPreferenceChangeListener
在单个 Preference 上设置。 适用于所有 Preference 对象。
Preference 即将更改其已保存值时调用,即使待处理值与已保存值相同也是如此。 仅在为 Preference 保存的值发生更改时调用。
只能通过 Preference 库调用。应用的单独部分可以更改已保存的值。 每当已保存值发生更改时调用,即使该值来自应用的单独部分也是如此。
在待处理值保存之前调用。 保存值后调用。
在使用 SharedPreferencesPreferenceDataStore 时调用。 仅在使用 SharedPreferences 时调用。

实现 OnPreferenceChangeListener

通过实现 OnPreferenceChangeListener,您可以监听对 Preference 的值的待定更改。然后,您可以验证是否发生了更改。例如,以下代码展示了如何监听键为 "name"EditTextPreference 值的变化:

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

接下来,您需要直接使用 setOnPreferenceChangeListener() 设置此监听器,如下所示:

Kotlin

preference.onPreferenceChangeListener = ...

Java

preference.setOnPreferenceChangeListener(...);

实现 OnSharedPreferenceChangeListener

在使用 SharedPreferences 保留 Preference 值时,您还可以使用 SharedPreferences.OnSharedPreferenceChangeListener 监听更改。这样,您就可以监听 Preference 保存的值发生更改的情况,例如在与服务器同步设置时。以下示例展示了如何监听键为 "name"EditTextPreference 值的变化:

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

使用 registerOnSharedPreferenceChangedListener() 注册监听器,如下所示:

Kotlin

preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(...)

Java

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

Kotlin

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

Java

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

为了正确管理 ActivityFragment 的生命周期,请在 onResume()onPause() 回调中注册和取消注册此监听器,如以下示例所示:

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

使用自定义数据存储区

虽然我们建议使用 SharedPreferences 保留 Preference 对象,但您也可以使用自定义数据存储区。如果您的应用将值保留在数据库中,或者值是特定于设备的,如以下示例所示,自定义数据存储区会非常有用。

实现数据存储区

如需实现自定义数据存储区,请创建一个扩展 PreferenceDataStore 的类。以下示例创建了一个处理 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.
    }
}

在主线程之外执行任何耗时的操作,以免阻塞界面。由于包含数据存储区的 FragmentActivity 可能会在保留值时被销毁,因此请序列化数据,以免丢失用户更改的任何值。

启用数据存储区

实现数据存储区后,请在 onCreatePreferences() 中设置新的数据存储区,以便 Preference 对象使用数据存储区保留值,而不是使用默认的 SharedPreferences。您可以为每个 Preference 或整个层次结构启用数据存储区。

如需为特定 Preference 启用自定义数据存储区,请对 Preference 调用 setPreferenceDataStore(),如以下示例所示:

Kotlin

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

Java

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

如需为整个层次结构启用自定义数据存储区,请对 PreferenceManager 调用 setPreferenceDataStore()

Kotlin

val preferenceManager = preferenceManager
preferenceManager.preferenceDataStore = dataStore

Java

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

为特定 Preference 设置的数据存储区会替换为相应层次结构设置的任何数据存储区。在大多数情况下,您需要为整个层次结构设置一个数据存储区。