2012-06-18 11 views
17

Mam trudności ze znalezieniem dobrego przykładu MultiSelectListPreference w interfejsie API systemu Android. Widziałem wiele odniesień do this blog, a to jest wynik końcowy, którego pragnę, nie chcę tworzyć klasy dla każdej preferencji wielokrotnego wyboru, którą chcę zaimplementować. Docelowo chcę zobaczyć xml preferencji dla prostego multi-select okna (które propaguje wartości dla dynamicznie), a także na wezwanie do addPreferencesFromResource(R.xml.preferences);Przykład MultiSelectListPreference

Obecnie mam:

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

i gdy próbuję zadzwonić addPreferencesFromResource w mojej działalności onCreate zadzwonić otrzymuję następujący błąd:

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 

czekam na odpowiedź!

+0

Po co mieć tyle kłopotów. W swoim fragmencie "onCreate" uzyskaj preferencje za pomocą "findPreference" i użyj metody "setEntries/setEntryValues" do ustawienia dynamicznego. – Ishaan

Odpowiedz

11

Sigrist jest poprawna, aby rozwiązać ten początkowy błąd widzisz. Wymagane są wartości domyślne, nawet jeśli są puste. Pomogło mi to, że chcę podać wartości pod RUNTIME, ale nie zadzieraj z pełną implementacją.

Zobacz ten kod, jak podać wartości w czasie wykonywania, bez konieczności obsługi pełnej implementacji.

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

W moim strings.xml

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

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

wiem, że to jest trochę stary pytanie, ale bardzo mi pomógł, więc tutaj jest moja odpowiedź!

42

musisz określić z obiektem 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" 
     /> 

Jeśli nie chcesz, wartości domyślne, należy utworzyć pustą tablicę w strings.xml

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

Jest to w zasadzie to, co sugeruje interfejs API systemu Android. Jestem zainteresowany dodaniem wpisów w RUNTIME. Nie ma nic dynamicznego w modyfikowaniu strings.xml – mohbandy

3

Mam utworzoną MultiSelectListPreference dla urządzeń uruchomienie Androida w interfejsie API wcześniej niż na poziomie 11.

  • Obsługuje listę otrzymywania list wyboru SELLLISTEN ect wartości.
  • Obsługuje automatyczne ustawianie podsumowania.
  • Załączone przykłady.

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

Nie można używać dynamicznych wpisów ładujących z tą klasą. – James