Android偏好设置:当用户未使用偏好设置屏幕时如何加载默认值?

130

我正在使用PreferenceActivity让用户设置一些值。我使用定义好的首选项XML文件来提供参数。

我已经为所有参数设置了android:defaultValue=""

当我启动我的应用程序时,我需要这些参数,如果它们还没有被手动设置,我希望使用默认值:

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean value = prefs.getBoolean("key"), false); 

然而,当android:defaultValue="true"时,我仍然得到了false。因此,看起来XML中设置的默认值只在初始化首选项屏幕时使用,但没有其他地方使用。

我不想在getBoolean()方法中硬编码默认值。那么,有没有一种方式可以在仅定义1个地方的情况下获取默认值?

6个回答

183
这个问题与我的类似:
onCreate方法中使用以下代码即可:

从XML文件中初始化首选项在主活动中

PreferenceManager.setDefaultValues(this, R.xml.preference, false);

它将从XML加载您的首选项,最后一个参数(readAgain)将保证用户首选项不会被覆盖。这意味着将readAgain参数设置为false意味着仅在此方法过去从未被调用时才设置默认值,因此您无需担心每次创建Activity时覆盖用户的设置。
请查看Android API中的PreferenceManager.setDefaultValues以进行进一步研究。

10
另外,如果您的应用程序具有多个入口点,请将其放置在“Application”的“onCreate()”中。 - S.D.
2
如果使用布尔值并将其默认为“false”,则此方法无效,因为在Android 2.x中不会创建默认条目。调用“.getBoolean(KEY, true)”将始终返回true。但是,在Android 4.x中可以正常工作。 - Gunnar Bernstein
11
将"readAgain"设置为true与用户偏好被覆盖无关。从Javadoc中可以看到:请注意,这将不会将首选项重置回其默认值。 - devconsole
这对我使用字符串和布尔型偏好设置有效。我正在使用Android 4.1.2。 - MidnightJava
1
对于那些在使用此解决方案时遇到问题(无法正常工作或部分工作或不总是工作),请参见Steve Waring在下面的答案(https://dev59.com/33E85IYBdhLWcg3wnU0d#25602205)。很可能您有几个共享首选项文件,即Android根据您的配置或混乱的代码创建了几个共享首选项文件。 - Hack06
显示剩余3条评论

27

13

在Pixel的被采纳的答案中:

PreferenceManager.setDefaultValues(this, R.xml.preference, false);
据说明,false 表示默认值不会被覆盖,但实际上它并不是这样。它只是一个效率标志,用于在您的应用程序具有多个入口点时停止解析。不幸的是,测试不是针对每个首选项文件进行的,因此如果您有多个首选项文件,则必须在除第一个文件外的所有文件中编写 true
如果您担心效率问题,可以编写类似以下内容的代码。
final static private int SPL = 1;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
if (sp.getInt("spl", 0) != SPL)
{
    PreferenceManager.setDefaultValues(this, R.xml.prefs1, true);
    PreferenceManager.setDefaultValues(this, R.xml.prefs2, true);
    sp.edit().putInt("spl", SPL).apply();
}
如果您要添加更多的共享首选项,只需将SPL设置为较高的数字。

3
作为一种替代方法,您可以始终创建一个用于设置默认值的bulk preferences.xml文件。例如,如果您有     R.xml.prefs_device,     R.xml.prefs_test 和     R.xml.prefs_admin.您可以创建一个包含上述所有首选项的首选项文件: R.xml.prefs_for_loading_default_values.然后使用以下代码: PreferenceManager.setDefaultValues(this, R.xml.prefs_for_loading_default_values, false); - Chantell Osejo
1
关于效率:如果您在Application子类的onCreate()中调用此函数(在清单中注册),它将仅在每个应用程序启动时调用一次。为了提高性能,更重要的是(如果有必要)不要在每次应用程序启动时进行解析(而是仅在第一次启动时进行),这就是false的作用。因此,这更多是一个问题,即您是否需要在每次启动时进行检查(例如,当添加新首选项时),或者是否在第一次启动时(或首选项重置)完成即可。 - user905686

2
例如,扩展 DialogPreference 我会这样做:
@Override
protected void onSetInitialValue(boolean restore, Object defaultValue) {
    super.onSetInitialValue(restore, defaultValue);

    if (restore) {
        mValue = shouldPersist() ? getPersistedString(mDefault) : mDefault;
    } else {
        mValue = mDefault;
    }
}

mDefault可以是:

  • mContext.getResources().getString(attrs.getAttributeResourceValue(androidns,"defaultValue", 100));
  • 你在R中索引的某些内容。

好的,我有点迷失在这里,不知道你想要实现什么。我不想调用DialogPreference,我需要当用户不使用首选项时的默认值。 - Peterdk
不要使用prefs.xml中的默认Preferences,而是可以创建自己的类。例如,您可以创建一个新的DialogPreference,扩展自DialogPreference并覆盖onSetInitialValue方法。 - Macarse

1

还要确保您以前从未使用过SharedPreferences。为了确保它们不被更改(这意味着setDefaultValues(this,xml,false)没有效果),请卸载您的应用程序并重新上传以确保没有值被触摸。这对我有帮助。


0

定义类继承自android.preference.Preference

public class IntegerPreference extends Preference {
    public IntegerPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public IntegerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public IntegerPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public IntegerPreference(Context context) {
        super(context);
    }

    @Override
    protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
        super.onSetInitialValue(restorePersistedValue, defaultValue);
        persistInt((Integer) defaultValue);
    }

    @Override
    protected Object onGetDefaultValue(TypedArray a, int index) {
        return a.getInt(index, -1);
    }
}

public class StringSetPreference extends Preference {
    public StringSetPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public StringSetPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public StringSetPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public StringSetPreference(Context context) {
        super(context);
    }

    @Override
    protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
        super.onSetInitialValue(restorePersistedValue, defaultValue);
        persistStringSet((Set<String>) defaultValue);
    }

    @Override
    protected Object onGetDefaultValue(TypedArray a, int index) {
        return Stream.of(a.getTextArray(index)).map(String::valueOf).collect(Collectors.toSet());
    }
}

定义首选项 XML 资源

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <com.ainirobot.preferencetest.IntegerPreference
        android:defaultValue="101"
        android:key="III" />
    <com.ainirobot.preferencetest.FloatPreference
        android:defaultValue="1.2"
        android:key="FFF" />
    <com.ainirobot.preferencetest.StringPreference
        android:defaultValue="SSS"
        android:key="SSS" />
    <com.ainirobot.preferencetest.BooleanPreference
        android:defaultValue="True"
        android:key="BBB" />
    <com.ainirobot.preferencetest.StringSetPreference
        android:defaultValue="@array/sset"
        android:key="SSET" />
</PreferenceScreen>

然后初始化默认值并访问

    PreferenceManager.setDefaultValues(this, R.xml.preferences, false);

    Map<String, ?> allKeys = PreferenceManager.getDefaultSharedPreferences(this).getAll();
    int iii = PreferenceManager.getDefaultSharedPreferences(this).getInt("III", -1);
    float fff = PreferenceManager.getDefaultSharedPreferences(this).getFloat("FFF", 0);
    Log.d(TAG, "allKeys=" + allKeys + " iii=" + iii + " fff=" + fff);

//日志记录

10-13 06:53:06.986 12594 12594 D MainActivity: allKeys={III=101, BBB=true, SSS=SSS, FFF=1.2, SSET=[XXX, ZZZ, YYY]} iii=101 fff=1.2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接