2012-06-18 15 views
17

Es fällt mir schwer, ein gutes Beispiel für die MultiSelectListPreference in der Android-API zu finden. Ich habe viele Verweise auf this blog gesehen, und das ist das Endergebnis, das ich wünsche, ich möchte keine Klasse für jede Multiselektions-Präferenz erstellen, die ich implementieren möchte. Letztlich möchte ich die Vorlieben xml für einen einfachen Multi-Select-Dialog sehen (was ich die Werte für dynamisch bevölkern werden) als auch auf den Aufruf zu addPreferencesFromResource(R.xml.preferences);MultiSelectListPreference Beispiel

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

und wenn ich versuche addPreferencesFromResource in meine Aktivitäten zu nennen onCreate nenne ich die folgende Störung erhalte:

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!

+0

Warum so viel Ärger nehmen. In Ihrem Fragment "onCreate" erhalten Sie die Präferenz mit "findPreference" und verwenden Sie die Methode "setEntries/setEntryValues" um dynamisch zu setzen. – Ishaan

Antwort

11

Sigrist korrekt ist, die Anfangsfehler lösen Sie sehen. Es benötigt Standardwerte, auch wenn es leer ist. Dies hat mir dabei geholfen, dass ich unter RUNTIME Werte bereitstellen möchte, aber nicht mit der vollständigen Implementierung zu tun haben.

In diesem Code erfahren Sie, wie ich zur Laufzeit Werte zur Verfügung stelle, ohne die vollständige Implementierung zu berücksichtigen.

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 meinem strings.xml

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

In meinem 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ß, das ist ein bisschen von einer alten Frage, aber es half mir, so ist hier meine Antwort!

42

Sie müssen den Defaultvalues ​​Eigenschaft

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

angeben Wenn Sie keine Standardwerte wollen, ein leeres Array in Ihrem strings.xml

<string-array name="empty_array"/> 
+4

Dies ist im Grunde, was die Android API vorschlägt. Ich bin daran interessiert, Einträge bei RUNTIME hinzuzufügen. Das Ändern von strings.xml ist nicht dynamisch. – mohbandy

3

erstelle ich MultiSelectListPreference für Geräte erstellt haben Android in der API vor Level 11 ausführen.

  • Unterstützt den ChangeListener, der die Liste der Sel Werte.
  • Unterstützt 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(); 
    } 

} 
+2

Dynamische Einträge, die mit dieser Klasse geladen werden, können nicht verwendet werden. – James