android multi-select preferenceactivity

android - Ejemplo de MultiSelectListPreference



multi-select preferenceactivity (4)

Me cuesta mucho encontrar un buen ejemplo de MultiSelectListPreference proporcionado en la API de Android. He visto muchas referencias a este blog , y aunque este es el resultado final que deseo, no quiero crear una clase para cada preferencia de selección múltiple que quiero implementar. En última instancia, quiero ver el xml de preferencias para un simple cuadro de diálogo de selección múltiple (en el que rellenaré los valores de forma dinámica), así como la llamada a addPreferencesFromResource(R.xml.preferences);

Actualmente tengo:

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

y cuando trato de llamar a addPreferencesFromResource en mi llamada de Actividades en Crear, recibo el siguiente error:

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

¡Espero su respuesta!


He creado MultiSelectListPreference para dispositivos que ejecutan Android en la API anterior al nivel 11.

  • Admite la lista de recepción de ChangeListener de los valores seleccionados.
  • Soporta la configuración automática de resumen.
  • Ejemplos adjuntos.

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


Necesitas especificar la propiedad 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 no desea valores predeterminados, cree una matriz vacía en sus strings.xml

<string-array name="empty_array"/>


Recibí el mismo error porque definí mi array.xml con entradas en valores grandes , pero no tenía el archivo en el paquete de valores predeterminados. Así que acabo de mover array.xml a los valores .


Sigrist es correcto, para solucionar el error inicial que estás viendo. Necesita valores predeterminados, incluso si está vacío. Esto me ayudó porque quiero proporcionar valores en RUNTIME , pero no meterme con la implementación completa.

Vea este código para saber cómo proporciono valores en tiempo de ejecución, sin tener que manejar la implementación completa.

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

En mis cadenas.xml

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

En mis preferencias.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"/>

Sé que esta es una pregunta un poco antigua, pero me ayudó, ¡así que aquí está mi respuesta!