Reputation: 518
The following code-snippet shows a fragment, which is to show some preferences including a custom preference (ColorPickerPreference
).
public static class PlayerEditFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.profile_player_edit);
...
The xml-file defining the preferences looks like this:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:key="prof_key_player"
android:title="Player" >
<EditTextPreference
android:key="prof_key_player_name"
android:title="Name" />
<de.jhouse.agt.view.dialog.ColorPickerPreference
android:defaultValue="2130837679"
android:key="prof_key_player_color"
android:title="Color" />
<de.jhouse.agt.view.dialog.NumberPickerPreference
android:defaultValue="0"
android:key="prof_key_player_pos"
android:title="Position" />
</PreferenceCategory>
</PreferenceScreen>
And the custom preference ColorPickerPreference
which enables the user to select a color from a list of predefined colors in a dialog:
public class ColorPickerPreference extends DialogPreference {
// the images to display
public static final Integer[] imageIDs = { R.drawable.player_white,
R.drawable.player_black, R.drawable.player_orange,
R.drawable.player_green, R.drawable.player_grey,
R.drawable.player_red, R.drawable.player_blue,
R.drawable.player_yellow, R.drawable.player_brown, };
private Gallery gallery;
private int value;
public ColorPickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ColorPickerPreference(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected View onCreateDialogView() {
final FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER;
gallery = new Gallery(getContext());
gallery.setLayoutParams(layoutParams);
gallery.setAdapter(new ImageAdapter(getContext()));
gallery.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
setValue(imageIDs[position]);
}
});
final FrameLayout dialogView = new FrameLayout(getContext());
dialogView.addView(gallery);
return dialogView;
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
gallery.setSelection(getValue(), true);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
setValue(gallery.getSelectedItemPosition());
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
Integer value = a.getInt(index, imageIDs[4]);
return value;
}
@Override
protected void onSetInitialValue(boolean restorePersistedValue,
Object defaultValue) {
setValue(restorePersistedValue ? getPersistedInt(imageIDs[4])
: (Integer) defaultValue);
}
public void setValue(int value) {
this.value = value;
persistInt(this.value);
}
public int getValue() {
return this.value;
}
/**
*
* @author Andy
*
*/
public static class ImageAdapter extends BaseAdapter {
private Context context;
private int itemBackground;
public ImageAdapter(Context c) {
context = c;
// sets a grey background; wraps around the images
TypedArray a = context.obtainStyledAttributes(R.styleable.MyGallery);
itemBackground = a.getResourceId(R.styleable.MyGallery_android_galleryItemBackground, 0);
a.recycle();
}
// returns the number of images
public int getCount() {
return imageIDs.length;
}
// returns the ID of an item
public Object getItem(int position) {
return position;
}
// returns the ID of an item
public long getItemId(int position) {
return position;
}
// returns an ImageView view
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(context);
imageView.setImageResource(imageIDs[position]);
imageView.setLayoutParams(new Gallery.LayoutParams(100, 100));
imageView.setBackgroundResource(itemBackground);
return imageView;
}
}
}
The problem now is, when the statetement addPreferencesFromResource(R.xml.profile_player_edit)
is executed, it throws a ClassCastException : Cannot cast String to int.
I cannot figure out what I did wrong, but if I exclude the custom preference ColorPickerPreference everything works fine?
Here's the complete Stacktrace:
02-10 15:35:45.778: D/AndroidRuntime(19737): Shutting down VM
02-10 15:35:45.798: E/AndroidRuntime(19737): FATAL EXCEPTION: main
02-10 15:35:45.798: E/AndroidRuntime(19737): Process: de.jhouse.agt, PID: 19737
02-10 15:35:45.798: E/AndroidRuntime(19737): java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.app.SharedPreferencesImpl.getInt(SharedPreferencesImpl.java:239)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.Preference.getPersistedInt(Preference.java:1697)
02-10 15:35:45.798: E/AndroidRuntime(19737): at de.jhouse.agt.view.dialog.ColorPickerPreference.onSetInitialValue(ColorPickerPreference.java:103)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.Preference.dispatchSetInitialValue(Preference.java:1514)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.Preference.onAttachedToHierarchy(Preference.java:1309)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.PreferenceGroup.addPreference(PreferenceGroup.java:167)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.PreferenceGroup.addItemFromInflater(PreferenceGroup.java:108)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.PreferenceGroup.addItemFromInflater(PreferenceGroup.java:45)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.GenericInflater.rInflate(GenericInflater.java:488)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.GenericInflater.rInflate(GenericInflater.java:493)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.GenericInflater.inflate(GenericInflater.java:326)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.GenericInflater.inflate(GenericInflater.java:263)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.PreferenceManager.inflateFromResource(PreferenceManager.java:272)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.preference.PreferenceFragment.addPreferencesFromResource(PreferenceFragment.java:300)
02-10 15:35:45.798: E/AndroidRuntime(19737): at de.jhouse.agt.activity.ProfileEditActivity$PlayerEditFragment.onCreate(ProfileEditActivity.java:620)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.app.Fragment.performCreate(Fragment.java:2075)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:868)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1082)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.app.BackStackRecord.run(BackStackRecord.java:833)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.app.FragmentManagerImpl$1.run(FragmentManager.java:452)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.os.Handler.handleCallback(Handler.java:739)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.os.Handler.dispatchMessage(Handler.java:95)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.os.Looper.loop(Looper.java:145)
02-10 15:35:45.798: E/AndroidRuntime(19737): at android.app.ActivityThread.main(ActivityThread.java:5834)
02-10 15:35:45.798: E/AndroidRuntime(19737): at java.lang.reflect.Method.invoke(Native Method)
02-10 15:35:45.798: E/AndroidRuntime(19737): at java.lang.reflect.Method.invoke(Method.java:372)
02-10 15:35:45.798: E/AndroidRuntime(19737): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
02-10 15:35:45.798: E/AndroidRuntime(19737): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)
Upvotes: 2
Views: 1224
Reputation: 113
For those who encounter this error without duplicate keys, the following solution may help:
Try to reinstall the app. You propably changed the class of the value of the preference during development, causing the the old value with an incompatible type to remain stored with that key, thus, preventing the setting to be compared and changed to the new one.
By uninstalling the app on the connected (or simulated) device, the preferences should get deleted too. The Key should then be free to be used by the new type of value.
If that is not the case, check your custom preference class. When you save the value as another type than the type you try to load it as, you can get the class cast exception too.
So: Check your custom Preference class' methods for consistency in their persistInt() and getPersistedInt() calls:
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
persistInt(getYourInteger());
}
}
@Override
protected void onSetInitialValue(
boolean restorePersistedValue,
Object defaultValue) {
int worstCaseDefault = 0;
int value;
if(restorePersistedValue) {
if (defaultValue == null) {
value = worstCaseDefault;
} else { //The following line is critical.
try { value = getPersistedInt(Integer.parseInt(defaultValue.toString())); }
catch (Exception e) {
Log.e("YourPreference", "OnSetInitialValue: ", e);
value = worstCaseDefault;
}
}
} else {
try { value = Integer.parseInt(defaultValue.toString()); }
catch (Exception e) {
Log.e("YourPreference", "OnSetInitialValue: ", e);
value = worstCaseDefault;
}
}
}
If this doesn't resolve the issue either, i'd guess that the preference survived the reinstallation. In that case you may want to look at the question that Stephen Kaiser commented on Andys own Answer.
Note, i only used the Integer type as example here, but it should work the same way with the other persist methods.
Upvotes: 2
Reputation: 518
Problem solved: Before I used the custom preference ColorPickerPreference I used a PreferenceList with the same preference-key. This PreferenceList saved the initial value as a String, so my new preference tried to convert some "old" String value into an Integer, which is not possible in this case. I just changed the key for the new preference.
However, is it possible to delete the values in the SharedPreferences, so errors like this can be avoided?
Upvotes: 0