Android PreferenceScreen - 我可以在不将首选项保存到 SharedPreferences 的情况下使用它吗?

Posted

技术标签:

【中文标题】Android PreferenceScreen - 我可以在不将首选项保存到 SharedPreferences 的情况下使用它吗?【英文标题】:Android PreferenceScreen - Can I use it without saving preferences to SharedPreferences? 【发布时间】:2013-01-16 00:01:38 【问题描述】:

我正在尝试使用 android PreferenceScreen 作为一种方便的方式来布局我的用户设置,但我不想将首选项保存到设备共享首选项中。这可能吗,还是我应该使用不同的机制,例如ListView

使用PreferenceScreen 类型似乎真的很方便,因为我需要不同的小部件(即开关、编辑文本)。但是我已经遇到了持久性问题,即。我输入的任何内容即使在我不希望的会话中也会保留。

settings.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_ >

    <Preference
        android:key="settings_type"
        android:title="@string/label_type" />

    <EditTextPreference
        android:key="settings_edit_name"
        android:title="@string/label_name"
        android:dialogTitle="Enter a name"
        android:singleLine="true" />

    <SwitchPreference
        android:key="settings_edit_state"
        android:title="@string/label_state"
        android:summary="Enable or disable the state" />

</PreferenceScreen>

【问题讨论】:

【参考方案1】:

我知道这是一个老问题,但我觉得它很有趣。只需将此属性设置为您的偏好,它不会被保存:

android:persistent="false"

【讨论】:

设置后,首选项监听器似乎根本没有收到任何通知。 太好了,这就是将视图与逻辑分开的关键!与Preference.setOnPreferenceChangeListener() 一起,它允许替代存储位置,并且可以与类似 MVVM 的系统一起使用。【参考方案2】:

我重新阅读了相应的docs 并确定了如何通过实现Preference.OnPreferenceChangeListener 接口来防止保存首选项。

公共静态接口Preference.OnPreferenceChangeListener

当值为 此首选项已被用户更改,即将设置 和/或坚持。这使客户有机会阻止设置 和/或保持值。

例子:

public class SettingsFragment extends PreferenceFragment 

    public static SettingsFragment newInstance(int index) 
        SettingsFragment f = new SettingsFragment();

        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);

        return f;
    

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        addPreferencesFromResource(R.layout.settings);

        // getArguments().getInt("index");

        EditTextPreference namePreference = (EditTextPreference) findPreference("settings_edit_name");
        namePreference.setOnPreferenceChangeListener(new NamePreferenceChangeListener());

    

    private class NamePreferenceChangeListener implements Preference.OnPreferenceChangeListener 

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) 
        // Do something else presumably and then return false to avoid saving the pref.
        return false;
    


【讨论】:

当从该方法返回 false 时,状态(例如 CheckBoxPreference)似乎根本没有改变,因此很难做任何事情。【参考方案3】:

您可以只使用线性布局并在其中放置所需组件的非首选版本。

【讨论】:

我正在尝试利用 PreferenceScreen,因为它是一个允许我在其中使用不同小部件的列表。在我的示例中,我不希望保存任何首选项。 这就是偏好小部件的重点,你真的只需要像EditTextSwitch这样的常规小部件,每个偏好小部件也有一个常规版本。只需将它们放置在您想要的任何布局中,然后为它们添加您需要的侦听器。 我同意,尝试覆盖偏好行为不是一个好主意。 组件的非首选版本是什么?例如,我应该使用什么来代替 EditTextPreference?我试过EditText,但是当我点击它时它无法设置摘要和显示弹出对话框。【参考方案4】:

由于偏好是一定要存储的,所以你可以随时在 onCreate 中清除它们

在 PreferenceFragment 的 onCreate 中试试这个

super.onCreate();
getPreferenceManager().setSharedPreferencesName("custom");
SharedPreferences sp = getPreferenceManager().getSharedPreferences();
SharedPreferences.Editor editor = sp.edit();
editor.clear();
editor.apply();

【讨论】:

如果你保存首选项只是为了以后删除它们,我觉得draksia的解决方案要好得多。【参考方案5】:

我建议创建PreferenceDataStore 的子类并将其分配给您的PreferenceManager

偏好数据存储

要实现并提供给 Preference 框架的数据存储接口。如果需要,这可用于替换默认的 android.content.SharedPreferences。

https://developer.android.com/reference/kotlin/androidx/preference/PreferenceDataStore

偏好管理器

public void setPreferenceDataStore (PreferenceDataStore dataStore)

设置一个 PreferenceDataStore 供与此管理器关联的所有首选项使用,这些首选项没有通过 Preference.setPreferenceDataStore(PreferenceDataStore) 分配的自定义 PreferenceDataStore。此外,如果设置了数据存储,则子首选项将不会使用 SharedPreferences,只要它们已分配给此管理器。

https://developer.android.com/reference/androidx/preference/PreferenceManager#setPreferenceDataStore(androidx.preference.PreferenceDataStore)

示例

自定义数据存储

    class CustomDataStore: PreferenceDataStore() 
    override fun putBoolean(key: String?, value: Boolean) 
        when (key) 
            knownKey -> // Do something
            anotherKnownKey -> // Do somthing else
        
    

    override fun putString(key: String?, value: String?) 
        when (key) 
            knownKey -> // Do something
            anotherKnownKey -> // Do something else
        
    

    // You can ignore unused types but make sure to still override to avoid UnsupportedOperationException
    override fun putFloat(key: String?, value: Float) 
    override fun putInt(key: String?, value: Int) 
    override fun putLong(key: String?, value: Long) 
    override fun putStringSet(key: String?, values: MutableSet<String>?) 

    override fun getBoolean(key: String?, defValue: Boolean): Boolean 
        return when (key) 
            knownKey -> // Do something
            anotherKnownKey -> // Do something else
            else -> defValue
        
    

    override fun getString(key: String?, defValue: String?): String? 
        return when (key) 
            knownKey -> // Do something
            anotherKnownKey -> // Do something else
            else -> defValue
        
    

注意:子类化时要小心,因为所有抽象的put() 方法都会抛出UnsupportedOperationException

PreferenceFragment 或 PreferenceFragmentCompat

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) 
    // Prevent saving to SharedPreferences, use a custom data store
    preferenceManager.preferenceDataStore = CustomDataStore()

【讨论】:

以上是关于Android PreferenceScreen - 我可以在不将首选项保存到 SharedPreferences 的情况下使用它吗?的主要内容,如果未能解决你的问题,请参考以下文章

PreferenceScreen的应用

创建首选项屏幕时找不到androidx.preference.PreferenceScreen

在我的“设置”片段中膨胀类 PreferenceScreen 时出错

在“设置”片段中夸大类PreferenceScreen的错误

Android Preference置灰显示

Android9.0 Settings 修改踩坑记录