ListPreference: use string-array as Entry and integer-array as Entry Values doesn't work

46,283

Solution 1

The answer is simple: because the Android is designed this way. It just uses String arrays for both entries and entry values and that's all. And I can't see any problem in this fact, since you can easily convert a String to an int using the Integer.parseInt() method. Hope this helps.

Solution 2

You can convert your entry values to strings to keep ListPreference happy and then convert them to ints when talking to the persistent data store.

  1. When setting the entry values, use strings instead of ints: "1", "2", "3" etc
  2. Make a custom IntListPreference that persists the values as ints
  3. In your preferences.xml file, change the <ListPreference> into a <your.app.package.IntListPreference>

IntListPreference.java

Here's a sample implementation. Tested and working on AndroidX Preference 1.0.0.

public class IntListPreference extends ListPreference {

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

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

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

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

    @Override
    protected boolean persistString(String value) {
        int intValue = Integer.parseInt(value);
        return persistInt(intValue);
    }

    @Override
    protected String getPersistedString(String defaultReturnValue) {
        int intValue;

        if (defaultReturnValue != null) {
            int intDefaultReturnValue = Integer.parseInt(defaultReturnValue);
            intValue = getPersistedInt(intDefaultReturnValue);
        } else {
            // We haven't been given a default return value, but we need to specify one when retrieving the value

            if (getPersistedInt(0) == getPersistedInt(1)) {
                // The default value is being ignored, so we're good to go
                intValue = getPersistedInt(0);
            } else {
                throw new IllegalArgumentException("Cannot get an int without a default return value");
            }
        }

        return Integer.toString(intValue);
    }

}

Solution 3

The answer is listed in List Preference Documentation.

int findIndexOfValue (String value)

will return the index for given value and the argument is taken as a String, so the entryValues array should be a string array to get this work.

Share:
46,283

Related videos on Youtube

Santacrab
Author by

Santacrab

Updated on July 05, 2022

Comments

  • Santacrab
    Santacrab almost 2 years

    I'm using in a settings.xml file a ListPreference. I want to show the user a list of 3 options to select. When the user chooses one of the options in the Settings, I get this error:

    java.lang.NullPointerException
        at android.preference.ListPreference.onDialogClosed(ListPreference.java:264)
        at android.preference.DialogPreference.onDismiss(DialogPreference.java:381)
        at android.app.Dialog$ListenersHandler.handleMessage(Dialog.java:1228)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4424)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
        at dalvik.system.NativeStart.main(Native Method)
    

    This is the code of the ListPreference:

    <ListPreference
        android:entries="@array/date_alignement"
        android:entryValues="@array/date_alignement_values"
        android:key="settings_date_alignement"
        android:summary="@string/settings_date_alignement_summary"
        android:title="@string/settings_date_alignement_title" />
    

    And here are the arrays I use to populate the entries:

    <string-array name="date_alignement">
        <item>"Top"</item>
        <item>"Center"</item>
        <item>"Bottom"</item>
    </string-array>
    <integer-array name="date_alignement_values">
        <item >0</item>
        <item >1</item>
        <item >2</item>
    </integer-array>
    

    In my onSharedPreferenceChanged I use those values in this way:

    @Override
    public void onSharedPreferenceChanged(
                SharedPreferences sharedPreferences, String key) {          
    
            //Text
            mAlignment =  mPrefs.getInt(PREF_ALIGNMENT, 1);
            switch (mAlignment) {
            case 0:
                offsetY = mHeight/3.0f;
                break;
    
            case 2:
                offsetY = mHeight*2.0f/3.0f;
                break;
    
            default:
                offsetY = mHeight/2.0f;
                break;
            }
    }
    

    If I use another string-array for the entryValues it works. For example if I use the same string array as values and entries:

        android:entries="@array/date_alignement"
        android:entryValues="@array/date_alignement"
    

    then I have to change my code a little but it works:

            if(mAlignment.equalsIgnoreCase("center")) {
                offsetY = mHeight/2.0f;
            } else if(mAlignment.equalsIgnoreCase("top")) {
                offsetY = mHeight/3.0f;
            } else if(mAlignment.equalsIgnoreCase("bottom")) {
                offsetY = mHeight*2.0f/3.0f;
            }
    

    Why I can't use a string-array and an integer-array for a ListPreference entries and values?

    • Yarik
      Yarik about 11 years
      I'm sory for stupid question, but what type of variable mAlignment do you use? and where did you get PREF_ALIGNMENT?
    • Santacrab
      Santacrab over 10 years
      In the first case mAlignment is an int. PREF_ALIGNMENT is the name of the entry in the SharedPreferences, where the alignment current value is stored
  • Santacrab
    Santacrab almost 12 years
    OK, still don't get why it's not supported. Obviousely I can and I will convert it, but if is possible to use a specific structure (integer-array) instead of using the string one and convert it in int, it should work :) Thanks anyway!
  • Egor
    Egor almost 12 years
    @Santacrab, If there were an integer array support, then there should also be float array support, double, char etc. It would be a big mess, so I think it's just easier to convert a String to whatever data type you need. Please accept the answer if you've found it useful.
  • Santacrab
    Santacrab almost 12 years
    actually the integer-array structure exists. The problem is that it's not work when paired to the string one.
  • Tjaart
    Tjaart over 11 years
    @Egor that is a silly reason. Of course you should be able to store different basic types. You can even serialise object types into your configs in .Net. And it isn't a big mess.
  • thom_nic
    thom_nic about 11 years
    I've run into the same issue. It's easy make a ListPreference that gives back ints. See: kvance.livejournal.com/1039349.html
  • theblang
    theblang over 10 years
    @ThomNichols Nice! I was already rolling my own anyway. That was pretty simple nonetheless.
  • Muhammad Babar
    Muhammad Babar over 9 years
    The answer is simple: because the Android is designed this way are you telling me android is rigidly designed? I'm sorry but this can be a lame excuse but not an answer!
  • njzk2
    njzk2 over 9 years
    typically, JSONObject.getInt tries to coerce values in int, sharedpreferences.getInt could do the same, and that would be sufficient
  • nizam.sp
    nizam.sp over 9 years
    @thom_nic: You made my day! The most elegant solution for this issue.
  • Gavriel
    Gavriel almost 9 years
    @thom_nic: unfortunatelly I get a ClassCastException in this line: int intValue = getPersistedInt(0);
  • Vivek Maru
    Vivek Maru over 6 years
    Please describe the issue properly.
  • Nolan Amy
    Nolan Amy over 5 years
    @thom_nic that livejournal link seems to be dead
  • HX_unbanned
    HX_unbanned about 3 years
    Thanks, @kasvith ! Could you add complete code sample, please?