130

I am using a PreferenceActivity to let the user set some values. I am feeding it the xml file with the defined preferences.

I have set all the android:defaultValue="" for them.

When I start my application, I need the preferences, or if they are not set yet manually, I want the default values:

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

However, when android:defaultValue="true" I still get false. So, it looks like the defaultValues set in the XML are not used anywhere but when initializing the preferences-screen.

I don't want to hardcode the default values in the getBoolean() method. So, is there a way get the default-values with only defining these in 1 place?

Peterdk
  • 15,625
  • 20
  • 101
  • 140

6 Answers6

183

this question is similar to mine:

initialize-preferences-from-xml-in-main-activity

Just use this code in onCreate method:

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

It will load your preferences from XML, and last parameter (readAgain) will guarantee that user preferences won't be overwritten. That means setting the readAgain argument to false means this will only set the default values if this method has never been called in the past so you don't need to worry about overriding the user's settings each time your Activity is created

Take a look into PreferenceManager.setDefaultValues in Android API for further investigation.

Gk Mohammad Emon
  • 6,084
  • 3
  • 42
  • 42
pixel
  • 24,905
  • 36
  • 149
  • 251
  • Can we use this over any another SharedPrefrence varible that we create ? – Amol Gupta Nov 12 '11 at 10:43
  • 10
    Also, If your App has multiple entry points, place it in `onCreate()` of `Application`. – S.D. Jan 07 '13 at 12:02
  • 2
    This does not work if using a boolean and defaulting to "false" as then the default entry will not be created in Android 2.x. A call to ".getBoolean(KEY, true)" will always return true. For Android 4.x it works. – Gunnar Bernstein Dec 03 '13 at 20:05
  • 11
    Setting `readAgain` to true has nothing to do with user preferences being overwritten. From the Javadoc: _Note: this will NOT reset preferences back to their default values._ – devconsole Jan 02 '14 at 18:12
  • This worked for me with String and boolean preferences. I'm using Android 4.1.2. – MidnightJava Mar 06 '14 at 02:35
  • 1
    For those who have problems with this solution (it doesn't work or works partially or not always) see Steve Waring's answer below (https://stackoverflow.com/a/25602205/4410376). Most likely you have several shared-prefs files, i.e. android is creating several shared-prefs files based on your configuration or messy code. – Hack06 Mar 22 '18 at 21:00
  • Also note that if you run your app once and then add new preferences, they won't get default values if you use `false` in `setDefaultValues`, as this method is only called once. Using `true` always checks the preference and sets default values for missing values. – user905686 Jun 10 '18 at 09:24
  • When using androidx, make sure you import the correct PreferenceManager from `import androidx.preference.PreferenceManager` otherwise you will encounter a _java.lang.ClassCastException: androidx.preference.PreferenceScreen cannot be cast to android.preference.GenericInflater$Parent_ – icyerasor Feb 11 '19 at 14:04
27

Be aware that if you are using
getSharedPreferences(String sharedPreferencesName, int sharedPreferencesMode)

to retrieve preferences you have to use
PreferenceManager.setDefaultValues(Context context, String sharedPreferencesName, int sharedPreferencesMode, int resId, boolean readAgain)
to set defaults!

For example:
PreferenceManager.setDefaultValues(this, PREFS_NAME, Context.MODE_PRIVATE, R.xml.preference, false);

I hope this can help someone.

Darpan
  • 5,623
  • 3
  • 48
  • 80
Francesco Vadicamo
  • 5,522
  • 35
  • 29
13

in Pixel's accepted answer:

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

it is stated that the false means that defaults won't be overwritten. This is not what it does, it is just an efficiency flag to stop the parsing if your application has more than one entry point. Unfortunately the test is not made per preference file, so if you have more than one preference file you must code true on all but the first.

If you are worried about efficiency, you could code something like this.

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

If you ever add more shared preferences, just set SPL to a hight number.

Steve Waring
  • 2,882
  • 2
  • 32
  • 37
  • 3
    As an alternative, you can always create a bulk preferences.xml that you ONLY use for setting default values. For example, if you have `R.xml.prefs_device`, `R.xml.prefs_test`, and `R.xml.prefs_admin`. You can create one prefs file that contains all of the prefs from the above: `R.xml.prefs_for_loading_default_values`. Then use that with `PreferenceManager.setDefaultValues(this, R.xml.prefs_for_loading_default_values, false);` – Chantell Osejo Nov 04 '15 at 18:44
  • 1
    Regarding efficiency: if you call this in `onCreate()` of a subclass of `Application` (registered in the manifest) it will only be called once per application start anyway. For performance it would be more relevant (if at all) to not do the parsing each time the app starts (instead only on it's first start) and this is what `false` does. So it is more a question of whether you need a check on each start (e.g. when new preferences might be added) or whether it's enough if done on the first start (or preferences reset). – user905686 Jun 10 '18 at 09:25
2

For example extending DialogPreference I do this:

@Override
protected void onSetInitialValue(boolean restore, Object defaultValue) {
    super.onSetInitialValue(restore, defaultValue);

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

mDefault can be:

  • mContext.getResources().getString(attrs.getAttributeResourceValue(androidns,"defaultValue", 100));
  • something you have indexed in R.
Macarse
  • 91,829
  • 44
  • 175
  • 230
  • Ok, I am a bit lost here about what you are trying to achieve. I don't want to call DialogPreference, I need the default value when the user doesn't user the Preferences. – Peterdk Apr 25 '10 at 14:46
  • Instead of using default Preferences in your prefs.xml you can create your own classes. For example you can create a new DialogPreference extending from DialogPreference and override the onSetInitialValue. – Macarse Apr 25 '10 at 18:21
1

Also make sure you have never used the SharedPreferences before. To make sure they are not changed (which means setDefaultValues(this,xml,false) has no effect) uninstall your App and upload it again to be sure no values are touched. This helped me.

wirthra
  • 153
  • 1
  • 10
0

define class extends 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());
    }
}

define preference XML resource

<?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>

then initialize default value and access

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

//Logcat

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
Yessy
  • 1,172
  • 1
  • 8
  • 13