web-dev-qa-db-fra.com

Exemple MultiSelectListPreference

J'ai de la difficulté à trouver un bon exemple de MultiSelectListPreference fourni dans l'API Android. J'ai vu de nombreuses références à ce blog , et bien que ce soit le résultat final que je souhaite, je ne souhaite pas créer de classe pour chaque préférence à sélection multiple que je veux implémenter. En fin de compte, je souhaite consulter les préférences XML pour un dialogue de sélection multiple simple (que je vais renseigner de manière dynamique), ainsi que pour l'appel à addPreferencesFromResource(R.xml.preferences);

Actuellement, j'ai: 

<MultiSelectListPreference
    Android:defaultValue=""
    Android:enabled="true"
    Android:entries="@array/pref_default_entries"
    Android:entryValues="@array/pref_default_values"
    Android:key="TargetList"
    Android:persistent="true"
    Android:summary="@string/TargetSummary"
    Android:title="@string/TargetTitle" />

et lorsque j'essaie d'appeler addPreferencesFromResource dans mon appel Activités onCreate, le message d'erreur suivant s'affiche:

06-18 13:59:30.690: E/AndroidRuntime(6052): FATAL EXCEPTION: main
06-18 13:59:30.690: E/AndroidRuntime(6052): Java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tracker/com.tracker.TrackerActivity}: Android.view.InflateException: Binary XML file line #37: Error inflating class Java.lang.reflect.Constructor
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:1818)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:1834)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.app.ActivityThread.access$500(ActivityThread.Java:122)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1027)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.os.Handler.dispatchMessage(Handler.Java:99)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.os.Looper.loop(Looper.Java:132)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.app.ActivityThread.main(ActivityThread.Java:4126)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Java.lang.reflect.Method.invokeNative(Native Method)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Java.lang.reflect.Method.invoke(Method.Java:491)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:844)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:602)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at dalvik.system.NativeStart.main(Native Method)
06-18 13:59:30.690: E/AndroidRuntime(6052): Caused by: Android.view.InflateException: Binary XML file line #37: Error inflating class Java.lang.reflect.Constructor
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.GenericInflater.createItem(GenericInflater.Java:397)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.GenericInflater.onCreateItem(GenericInflater.Java:417)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.GenericInflater.createItemFromTag(GenericInflater.Java:428)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.GenericInflater.rInflate(GenericInflater.Java:481)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.GenericInflater.inflate(GenericInflater.Java:326)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.GenericInflater.inflate(GenericInflater.Java:263)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.PreferenceManager.inflateFromResource(PreferenceManager.Java:269)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.PreferenceActivity.addPreferencesFromResource(PreferenceActivity.Java:1366)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at com.tracker.TrackerActivity.onCreate(TrackerActivity.Java:30)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.Java:1050)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:1782)
06-18 13:59:30.690: E/AndroidRuntime(6052):     ... 11 more
06-18 13:59:30.690: E/AndroidRuntime(6052): Caused by: Java.lang.reflect.InvocationTargetException
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Java.lang.reflect.Constructor.constructNative(Native Method)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Java.lang.reflect.Constructor.newInstance(Constructor.Java:416)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.GenericInflater.createItem(GenericInflater.Java:383)
06-18 13:59:30.690: E/AndroidRuntime(6052):     ... 21 more
06-18 13:59:30.690: E/AndroidRuntime(6052): Caused by: Java.lang.NullPointerException
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.content.res.AssetManager.getResourceTextArray(AssetManager.Java:215)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.content.res.Resources.getTextArray(Resources.Java:435)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.content.res.TypedArray.getTextArray(TypedArray.Java:628)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.MultiSelectListPreference.onGetDefaultValue(MultiSelectListPreference.Java:210)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.Preference.<init>(Preference.Java:257)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.DialogPreference.<init>(DialogPreference.Java:69)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.DialogPreference.<init>(DialogPreference.Java:90)
06-18 13:59:30.690: E/AndroidRuntime(6052):     at Android.preference.MultiSelectListPreference.<init>(MultiSelectListPreference.Java:49)
06-18 13:59:30.690: E/AndroidRuntime(6052):     ... 24 more

J'attends votre réponse avec impatience!

19
mohbandy

Sigrist est correct, pour résoudre l'erreur initiale que vous voyez. Il a besoin des valeurs par défaut fournies, même si c'est vide. Cela m'a aidé dans le sens où je veux fournir des valeurs àRUNTIME, mais ne gêne pas l'implémentation complète. 

Consultez ce code pour savoir comment je fournis des valeurs au moment de l'exécution, sans avoir à gérer l'implémentation complète.

public class CalendarListPreference extends MultiSelectListPreference {

ContentResolver cr;
Cursor cursor;
String[] projection = new String[] {CalendarContract.Calendars.NAME, CalendarContract.Calendars.CALENDAR_DISPLAY_NAME};
String selection = "(" + CalendarContract.Calendars.VISIBLE + " = ?)";
String[] selectionArgs = new String[] { "1" };

public CalendarListPreference(Context context, AttributeSet attrs) {
    super(context, attrs);

    List<CharSequence> entries = new ArrayList<CharSequence>();
    List<CharSequence> entriesValues = new ArrayList<CharSequence>();

    cr = context.getContentResolver();
    cursor = cr.query(CalendarContract.Calendars.CONTENT_URI, projection, selection, selectionArgs, null);

    while (cursor.moveToNext()) {
        String name = cursor.getString(0);
        String displayName = cursor.getString(1);

        entries.add(name);
        entriesValues.add(displayName);
    }

    setEntries(entries.toArray(new CharSequence[]{}));
    setEntryValues(entriesValues.toArray(new CharSequence[]{}));
}
}

Dans mon strings.xml

<string-array name="pref_calendar_list_default">
</string-array>

Dans mon preferences.xml

<com.mynameistodd.autovolume.CalendarListPreference
Android:defaultValue="@array/pref_calendar_list_default"
Android:key="@string/pref_calendar_list_key"
Android:summary="@string/pref_calendar_list_summary"
Android:title="@string/pref_calendar_list_title"
Android:dependency="@string/pref_calendar_enabled_key"/>

Je sais que c'est une question un peu ancienne, mais cela m'a aidé, alors voici ma réponse!

12
Todd DeLand

Vous devez spécifier la propriété defaultValues

<MultiSelectListPreference
        Android:dialogTitle="@string/mode_repeat"
        Android:key="mode_repeat"
        Android:summary=""        
        Android:title="@string/mode_repeat"
        Android:entries="@array/weekdays"
        Android:entryValues="@array/weekdays_values"
        Android:defaultValue="@array/empty_array"
        />

Si vous ne voulez pas de valeurs par défaut, créez un tableau vide dans votre strings.xml.

<string-array name="empty_array"/>
44
Sigrist

J'ai créé MultiSelectListPreference pour les appareils exécutant Android dans l'API antérieure au niveau 11. 

  • Prend en charge la liste de réception des valeurs sélectionnées par ChangeListener. 
  • Prise en charge de la configuration automatique du résumé. 
  • Exemples attachés.

https://Gist.github.com/cardil/4754571

package pl.wavesoftware.widget;

import Java.util.ArrayList;
import Java.util.Arrays;
import Java.util.Iterator;
import Java.util.List;

import Android.app.AlertDialog.Builder;
import Android.content.Context;
import Android.content.DialogInterface;
import Android.content.DialogInterface.OnMultiChoiceClickListener;
import Android.content.res.TypedArray;
import Android.preference.ListPreference;
import Android.util.AttributeSet;

public class MultiSelectListPreference extends ListPreference {

    private String separator;
    private static final String DEFAULT_SEPARATOR = "\u0001\u0007\u001D\u0007\u0001";
    private boolean[] entryChecked;

    public MultiSelectListPreference(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        entryChecked = new boolean[getEntries().length];
        separator = DEFAULT_SEPARATOR;
    }

    public MultiSelectListPreference(Context context) {
        this(context, null);
    }

    @Override
    protected void onPrepareDialogBuilder(Builder builder) {
        CharSequence[] entries = getEntries();
        CharSequence[] entryValues = getEntryValues();
        if (entries == null || entryValues == null
                || entries.length != entryValues.length) {
            throw new IllegalStateException(
                    "MultiSelectListPreference requires an entries array and an entryValues "
                            + "array which are both the same length");
        }

        restoreCheckedEntries();
        OnMultiChoiceClickListener listener = new DialogInterface.OnMultiChoiceClickListener() {
            public void onClick(DialogInterface dialog, int which, boolean val) {
                entryChecked[which] = val;
            }
        };
        builder.setMultiChoiceItems(entries, entryChecked, listener);
    }

    private CharSequence[] unpack(CharSequence val) {
        if (val == null || "".equals(val)) {
            return new CharSequence[0];
        } else {
            return ((String) val).split(separator);
        }
    }

    /**
     * Gets the entries values that are selected
     * 
     * @return the selected entries values
     */
    public CharSequence[] getCheckedValues() {
        return unpack(getValue());
    }

    private void restoreCheckedEntries() {
        CharSequence[] entryValues = getEntryValues();

        // Explode the string read in sharedpreferences
        CharSequence[] vals = unpack(getValue());

        if (vals != null) {
            List<CharSequence> valuesList = Arrays.asList(vals);
            for (int i = 0; i < entryValues.length; i++) {
                CharSequence entry = entryValues[i];
                entryChecked[i] = valuesList.contains(entry);
            }
        }
    }

    @Override
    protected void onDialogClosed(boolean positiveResult) {
        List<CharSequence> values = new ArrayList<CharSequence>();

        CharSequence[] entryValues = getEntryValues();
        if (positiveResult && entryValues != null) {
            for (int i = 0; i < entryValues.length; i++) {
                if (entryChecked[i] == true) {
                    String val = (String) entryValues[i];
                    values.add(val);
                }
            }

            String value = join(values, separator);
            setSummary(prepareSummary(values));
            setValueAndEvent(value);
        }
    }

    private void setValueAndEvent(String value) {
        if (callChangeListener(unpack(value))) {
            setValue(value);
        }
    }

    private CharSequence prepareSummary(List<CharSequence> joined) {
        List<String> titles = new ArrayList<String>();
        CharSequence[] entryTitle = getEntries();
        CharSequence[] entryValues = getEntryValues();
        int ix = 0;
        for (CharSequence value : entryValues) {
            if (joined.contains(value)) {
                titles.add((String) entryTitle[ix]);
            }
            ix += 1;
        }
        return join(titles, ", ");
    }

    @Override
    protected Object onGetDefaultValue(TypedArray typedArray, int index) {
        return typedArray.getTextArray(index);
    }

    @Override
    protected void onSetInitialValue(boolean restoreValue,
            Object rawDefaultValue) {
        String value = null;
        CharSequence[] defaultValue;
        if (rawDefaultValue == null) {
            defaultValue = new CharSequence[0];
        } else {
            defaultValue = (CharSequence[]) rawDefaultValue;
        }
        List<CharSequence> joined = Arrays.asList(defaultValue);
        String joinedDefaultValue = join(joined, separator);
        if (restoreValue) {
            value = getPersistedString(joinedDefaultValue);
        } else {
            value = joinedDefaultValue;
        }

        setSummary(prepareSummary(Arrays.asList(unpack(value))));
        setValueAndEvent(value);
    }

    /**
     * Joins array of object to single string by separator
     * 
     * Credits to kurellajunior on this post
     * http://snippets.dzone.com/posts/show/91
     * 
     * @param iterable
     *            any kind of iterable ex.: <code>["a", "b", "c"]</code>
     * @param separator
     *            separetes entries ex.: <code>","</code>
     * @return joined string ex.: <code>"a,b,c"</code>
     */
    protected static String join(Iterable<?> iterable, String separator) {
        Iterator<?> oIter;
        if (iterable == null || (!(oIter = iterable.iterator()).hasNext()))
            return "";
        StringBuilder oBuilder = new StringBuilder(String.valueOf(oIter.next()));
        while (oIter.hasNext())
            oBuilder.append(separator).append(oIter.next());
        return oBuilder.toString();
    }

}
3
cardil

J'ai eu la même erreur parce que j'ai défini mon array.xml avec des entrées dans values-large , mais je n'avais pas le fichier dans la valeur par défaut values ​​package. Je viens donc de déplacer array.xml into values ​​.

0
Andrew