wake-up-neo.com

MultiSelectListPreference-Beispiel

Es fällt mir schwer, ein gutes Beispiel für die in der Android-API enthaltene MultiSelectListPreference zu finden. Ich habe viele Verweise auf dieses Blog gesehen, und da dies das Endergebnis ist, das ich mir wünsche, möchte ich keine Klasse für jede Multi-Select-Präferenz erstellen, die ich implementieren möchte. Letztendlich möchte ich die Voreinstellungen xml für einen einfachen Mehrfachauswahldialog sehen (für den ich die Werte dynamisch ausfüllen werde) sowie den Aufruf von addPreferencesFromResource(R.xml.preferences);.

Zur Zeit habe ich: 

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

wenn ich versuche, addPreferencesFromResource in meinen Activities onCreate aufzurufen, erhalte ich die folgende Fehlermeldung:

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

Ich freue mich auf Ihre Antwort!

19
mohbandy

Sigrist ist richtig, um den anfänglichen Fehler zu beheben, den Sie sehen. Es müssen Standardwerte angegeben werden, auch wenn sie leer sind. Dies hat mir dabei geholfen, dass ich Werte zurLAUFZEITbereitstellen möchte, aber mich nicht mit der vollständigen Implementierung beschäftige. 

In diesem Code erfahren Sie, wie ich zur Laufzeit Werte bereitstelle, ohne die vollständige Implementierung durchführen zu müssen.

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[]{}));
}
}

In meiner strings.xml

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

In meiner 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"/>

Ich weiß, dass dies eine alte Frage ist, aber es hat mir geholfen. Hier ist meine Antwort!

12
Todd DeLand

Sie müssen die Eigenschaft defaultValues ​​angeben

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

Wenn Sie keine Standardwerte wünschen, erstellen Sie ein leeres Array in Ihrer strings.xml

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

Ich habe MultiSelectListPreference für Geräte erstellt, auf denen Android in der API vor Level 11 ausgeführt wird. 

  • Unterstützt den ChangeListener-Empfang von ausgewählten Werten. 
  • Unterstützt die automatische Einstellung der Zusammenfassung. 
  • Beispiele beigefügt.

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

Ich habe den gleichen Fehler erhalten, weil ich meine array.xml mit Einträgen in values-large definiert habe, die Datei jedoch nicht im standardmäßigen values ​​package hatte. Also habe ich gerade array.xml in values ​​verschoben.

0
Andrew