ListPreference: используйте string-array как Entry и integer-array, поскольку значения Entry не работают
Я использую в файле settings.xml ListPreference. Я хочу показать пользователю список из 3 возможных вариантов. Когда пользователь выбирает один из параметров в настройках, я получаю эту ошибку:
java.lang.NullPointerException
at android.preference.ListPreference.onDialogClosed(ListPreference.java:264)
at android.preference.DialogPreference.onDismiss(DialogPreference.java:381)
at android.app.Dialog$ListenersHandler.handleMessage(Dialog.java:1228)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Это код ListPreference:
<ListPreference
android:entries="@array/date_alignement"
android:entryValues="@array/date_alignement_values"
android:key="settings_date_alignement"
android:summary="@string/settings_date_alignement_summary"
android:title="@string/settings_date_alignement_title" />
И вот массивы, которые я использую для заполнения записей:
<string-array name="date_alignement">
<item>"Top"</item>
<item>"Center"</item>
<item>"Bottom"</item>
</string-array>
<integer-array name="date_alignement_values">
<item >0</item>
<item >1</item>
<item >2</item>
</integer-array>
В моем onSharedPreferenceChanged я использую эти значения следующим образом:
@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
//Text
mAlignment = mPrefs.getInt(PREF_ALIGNMENT, 1);
switch (mAlignment) {
case 0:
offsetY = mHeight/3.0f;
break;
case 2:
offsetY = mHeight*2.0f/3.0f;
break;
default:
offsetY = mHeight/2.0f;
break;
}
}
Если я использую другой строковый массив для entryValues , он работает. Например, если я использую тот же массив строк, что и значения и записи:
android:entries="@array/date_alignement"
android:entryValues="@array/date_alignement"
тогда мне нужно немного изменить код, но он работает:
if(mAlignment.equalsIgnoreCase("center")) {
offsetY = mHeight/2.0f;
} else if(mAlignment.equalsIgnoreCase("top")) {
offsetY = mHeight/3.0f;
} else if(mAlignment.equalsIgnoreCase("bottom")) {
offsetY = mHeight*2.0f/3.0f;
}
Почему я не могу использовать строковый массив и целочисленный массив для записей и значений ListPreference?
Ответы
Ответ 1
Ответ прост: потому что Android разработан таким образом. Он просто использует массивы String
как для записей, так и для входных значений и для всех. И я не вижу никакой проблемы в этом факте, так как вы можете легко преобразовать String
в int
с помощью метода Integer.parseInt()
. Надеюсь, это поможет.
Ответ 2
Ответ указан в Список предпочтительной документации.
int findIndexOfValue (String value)
вернет индекс для данного значения, и аргумент будет принят как String, поэтому массив entryValues должен быть массивом строк, чтобы получить эту работу.
Ответ 3
Вы можете преобразовать значения ListPreference
в строки, чтобы сохранить ListPreference
а затем преобразовать их обратно при обращении к постоянному хранилищу данных.
- При установке значений ввода используйте строки вместо целых:
"1", "2", "3"
т.д. - Создайте пользовательскую
IntListPreference
которая сохраняет значения в виде целых - В вашем файле
preferences.xml
измените <ListPreference>
на <your.app.package.IntListPreference>
IntListPreference.java
Вот пример реализации. Протестировано и работает на AndroidX Preference 1.0.0.
public class IntListPreference extends ListPreference {
public IntListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public IntListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public IntListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public IntListPreference(Context context) {
super(context);
}
@Override
protected boolean persistString(String value) {
int intValue = Integer.parseInt(value);
return persistInt(intValue);
}
@Override
protected String getPersistedString(String defaultReturnValue) {
int intValue;
if (defaultReturnValue != null) {
int intDefaultReturnValue = Integer.parseInt(defaultReturnValue);
intValue = getPersistedInt(intDefaultReturnValue);
} else {
// We haven't been given a default return value, but we need to specify one when retrieving the value
if (getPersistedInt(0) == getPersistedInt(1)) {
// The default value is being ignored, so we're good to go
intValue = getPersistedInt(0);
} else {
throw new IllegalArgumentException("Cannot get an int without a default return value");
}
}
return Integer.toString(intValue);
}
}
Ответ 4
Следующие работали для меня:
String objectName = prefs.getString("listPrefMelodyYd1", "");
switch (objectName.toUpperCase()) {
case "1":
playSound(catSound);
break;
case "2":
playSound(dogSound);
break;
case "3":
playSound(cowSound);
break;
}