web-dev-qa-db-fra.com

ListPreference: utiliser string-array comme Entry et integer-array comme Entry Values ​​ne fonctionne pas

J'utilise dans un fichier settings.xml un ListPreference. Je veux montrer à l'utilisateur une liste de 3 options à sélectionner. Lorsque l'utilisateur choisit l'une des options dans les paramètres, j'obtiens cette erreur:

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)

Voici le code de 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" />

Et voici les tableaux que j'utilise pour remplir les entrées:

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

Dans mon onSharedPreferenceChanged, j'utilise ces valeurs de cette manière:

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

Si j'utilise un autre tableau de chaînes pour entryValues cela fonctionne. Par exemple, si j'utilise le même tableau de chaînes que les valeurs et les entrées:

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

alors je dois changer un peu mon code mais ça marche:

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

Pourquoi je ne peux pas utiliser un tableau de chaînes et un tableau d'entiers pour les entrées et les valeurs ListPreference?

69
Santacrab

La réponse est simple: parce que le Android est conçu de cette façon. Il utilise simplement des tableaux String pour les entrées et les valeurs d'entrée et c'est tout. Et je ne vois aucun problème dans ce cas, puisque vous pouvez facilement convertir un String en int en utilisant la méthode Integer.parseInt(). J'espère que cela vous aidera.

82
Egor

La réponse est répertoriée dans List Preference Documentation .

int findIndexOfValue (String value)

renverra l'index pour la valeur donnée et l'argument est pris comme une chaîne, donc le tableau entryValues ​​doit être un tableau de chaînes pour obtenir ce travail.

3
kasper

Vous pouvez convertir vos valeurs d'entrée en chaînes pour garder ListPreference heureux, puis les convertir en ints lorsque vous parlez au magasin de données persistantes.

  1. Lors de la définition des valeurs d'entrée, utilisez des chaînes plutôt que des entiers: "1", "2", "3" etc
  2. Créer un IntListPreference personnalisé qui conserve les valeurs sous forme d'entiers
  3. Dans votre preferences.xml fichier, modifiez le <ListPreference> dans une <your.app.package.IntListPreference>

IntListPreference.Java

Voici un exemple d'implémentation. Testé et fonctionnant sur 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);
    }

}
1
Sam