android-support-preference icon indicating copy to clipboard operation
android-support-preference copied to clipboard

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer SeekBarPreference.onSetInitialValue

Open dirkam opened this issue 6 years ago • 22 comments

Can you please look into this crash? From time to time I see this crash reported, but it's a rare one.

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{.MyActivity}: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2984)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
       at android.app.ActivityThread.-wrap14(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6776)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Caused by java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
       at android.app.SharedPreferencesImpl.getInt(SharedPreferencesImpl.java:242)
       at android.support.v7.preference.Preference.getPersistedInt(Preference.java:1709)
       at net.xpece.android.support.preference.SeekBarPreference.onSetInitialValue(SeekBarPreference.java:274)
       at android.support.v7.preference.Preference.dispatchSetInitialValue(Preference.java:6517)
       at android.support.v7.preference.Preference.onAttachedToHierarchy(Preference.java:1257)
       at android.support.v7.preference.PreferenceGroup.addPreference(PreferenceGroup.java:194)
       at android.support.v7.preference.XpPreferenceInflater.android.support.v7.preference.PreferenceGroup.addItemFromInflater(XpPreferenceInflater.java:4126)
       at android.support.v7.preference.XpPreferenceInflater.rInflate(XpPreferenceInflater.java:293)
       at android.support.v7.preference.XpPreferenceInflater.rInflate(XpPreferenceInflater.java:293)
       at android.support.v7.preference.XpPreferenceInflater.inflate(XpPreferenceInflater.java:103)
       at android.support.v7.preference.PreferenceInflater.inflate$7af30e91(PreferenceInflater.java:112)
       at android.support.v7.preference.XpPreferenceManager.inflateFromResource$6154c3e6(XpPreferenceManager.java:67)
       at .MyFragment.android.support.v7.preference.PreferenceFragmentCompat.addPreferencesFromResource(MyFragment.java:9432)
       at android.support.v7.preference.XpPreferenceFragment.onCreatePreferences(XpPreferenceFragment.java:54)
       at android.support.v7.preference.PreferenceFragmentCompat.onCreate(PreferenceFragmentCompat.java:224)
       at android.support.v4.app.Fragment.performCreate(Fragment.java:2329)
       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1377)
       at android.support.v4.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1109)
       at android.support.v4.app.FragmentTransition.calculateFragments(FragmentTransition.java:996)
       at android.support.v4.app.FragmentTransition.startTransitions(FragmentTransition.java:99)
       at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2364)
       at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)
       at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229)
       at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3221)
       at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3171)
       at android.support.v4.app.FragmentActivity.android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentActivity.java:16192)
       at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:177)
       at .MyActivity.onStart(MyActivity.java)
       at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1256)
       at android.app.Activity.performStart(Activity.java:6972)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2937)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
       at android.app.ActivityThread.-wrap14(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6776)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

dirkam avatar Sep 27 '17 19:09 dirkam

Hi, what have you tried so far?

Looks like somehow a string got into a preference that's supposed to be integer.

  • You updated the preference manually with a value of wrong type.
  • You mixed up preference keys.
  • You accidentally used the same key for two very different preferences.

I recommend Stetho for investigating what's actually stored in there in case this happens on your own device.

consp1racy avatar Sep 27 '17 20:09 consp1racy

I've checked these but I couldn't find anything. Since it's crashing at addPreferencesFromResource I think it might be something with the XML?

This is how I use it:

<net.xpece.android.support.preference.SeekBarPreference xmlns:app="http://schemas.android.com/apk/res-auto"
                                                                        android:key="volume"
                                                                        android:title="@string/settings_sound_volume"/>

Can it be that android:defaultValue is not set in XML? If so, then how come that it only causes a crash very rarely?

dirkam avatar Sep 30 '17 14:09 dirkam

It's not XML related, it crashes because it's trying to load the value from hard drive and it finds a String instead of the expected integer.

Did you by any chance use the same key "volume" for anything else? Or did you edit shared preferences manually? This is the only thing that comes to my mind...

Unless... "volume" is a very generic name, some library you're using may be writing in your default shared preference file.

Can it be that android:defaultValue is not set in XML?

In that case the default value is 0.

consp1racy avatar Sep 30 '17 14:09 consp1racy

Is ClasscastException fatal error?

Devarajrc avatar Jan 30 '18 09:01 Devarajrc

It is.

dirkam avatar Jan 30 '18 09:01 dirkam

@dirkam I never asked, what device did this happen on? Can you reproduce it?

consp1racy avatar Jan 30 '18 13:01 consp1racy

Unfortunately, I can't reproduce it. I still see this crash, though. (Did change the previously mentioned "volume" generic name, didn't help)

Happens on a wide variety of devices.

image

dirkam avatar Jan 30 '18 13:01 dirkam

@dirkam Could you release a version of your app with some added logging? I'd like to see what value is stored in that preference. Perhaps then I'll be able to guess where it came from.

When your settings activity starts, before it loads the preference fragment, check if the preference file contains the value and if it does, try to get it. You'll need to try-catch all the types because we don't know what's the type of value.

if (prefs.contains("volume") {
    try {
        val out = prefs.getInt("volume")
        Crashlytics.logException(RuntimeException("Volume is int = '$out'"))
    } catch (ex: ClassCastException) {
        try {
            val out = prefs.getString("volume")
            Crashlytics.logException(RuntimeException("Volume is String = '$out'"))
        } catch (ex : ClassCastException) {
            // ...
        }
    }
}

You can get the default preferences with

val prefs = XpPreferenceManager.getDefaultSharedPreferences(this)

consp1racy avatar Jan 30 '18 15:01 consp1racy

Thanks, will do that and keep monitoring it.

dirkam avatar Jan 31 '18 17:01 dirkam

Finally, I managed to catch this live (based on a user report, so I'm still unable to reproduce it locally).

This is extremely weird. I have 5 SeekBarPreference and 1 SeekBarDialogPreference. In a way, all of these are affected.

  • 2 of them were missing from the prefs, which simply would not be possible, only on a fresh install but the app has been used for almost a year.
  • 3 of them returned ClassCastException and were stored as String. Seemingly numerical value, but for 1 of these the actual value should be different based on the user settings.
  • 1 of them is Integer, but the value stored is different from what it should be.

This is really weird. I've checked all the relevant code 3 times and I don't put String into these ever (it would also result in a more frequent crash, I guess).

Not sure if this helps.

I think I can add some workaround locally but would be great to get to the bottom of this.

dirkam avatar Feb 28 '18 05:02 dirkam

After adding the workaround (basically, I check for these errors and load a default value if there is an issue), it doesn't crash on the user's device anymore. However, I noticed in the logs that there are errors thrown for MultiSelectListPreference, too. Most probably we haven't seen this yet because the app was crashing prior to loading these preferences. I have a feeling that this is coming from the similar weird issue with the stored values. I have 4 MultiSelectListPreference and all 4 throws this error. This issue doesn't crash the app, though. I think the rest of the preferences should be fine as there is no crash or any other error in the logs.

 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1518)
 	at java.lang.reflect.Method.invoke(Native Method)
 	at android.app.ActivityThread.main(ActivityThread.java:6776)
 	at android.os.Looper.loop(Looper.java:154)
 	at android.os.Handler.dispatchMessage(Handler.java:102)
 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
 	at android.app.ActivityThread.-wrap14(ActivityThread.java)
 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2937)
 	at android.app.Activity.performStart(Activity.java:6973)
 	at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1256)
 	at android.support.v7.app.e.onStart(AppCompatActivity.java:177)
 	at android.support.v4.app.g.onStart(FragmentActivity.java:16192)
 	at android.support.v4.app.l.q(FragmentManager.java:3181)
 	at android.support.v4.app.l.c(FragmentManager.java:3231)
 	at android.support.v4.app.l.k(FragmentManager.java:2239)
 	at android.support.v4.app.l.a(FragmentManager.java:2332)
 	at android.support.v4.app.l.a(FragmentManager.java:2374)
 	at android.support.v4.app.q.a(FragmentTransition.java:115)
 	at android.support.v4.app.q.a(FragmentTransition.java:1070)
 	at android.support.v4.app.q.a(FragmentTransition.java:1187)
 	at android.support.v4.app.l.a(FragmentManager.java:1377)
 	at android.support.v4.app.Fragment.performCreate(Fragment.java:2246)
 	at android.support.v7.preference.f.onCreate(PreferenceFragmentCompat.java:224)
 	at android.support.v7.preference.m.a(XpPreferenceFragment.java:54)
 	at com.myapp.q.b(SettingsFragment.java:)
 	at android.support.v7.preference.q.a(XpPreferenceManager.java:67)
 	at android.support.v7.preference.h.a(PreferenceInflater.java:112)
 	at android.support.v7.preference.p.a(XpPreferenceInflater.java:103)
 	at android.support.v7.preference.p.a(XpPreferenceInflater.java:293)
 	at android.support.v7.preference.p.a(XpPreferenceInflater.java:293)
 	at android.support.v7.preference.p.a(XpPreferenceInflater.java:293)
 	at android.support.v7.preference.p.a(XpPreferenceInflater.java:293)
 	at android.support.v7.preference.p.a(XpPreferenceInflater.java:4126)
 	at android.support.v7.preference.PreferenceGroup.b(PreferenceGroup.java:194)
 	at android.support.v7.preference.Preference.a(Preference.java:1256)
 	at android.support.v7.preference.Preference.a(Preference.java:6516)
 	at net.xpece.android.support.preference.MultiSelectListPreference.a(MultiSelectListPreference.java:195)
 	at android.support.v7.preference.l.b(XpPreferenceCompat.java:90)
 	at net.xpece.android.support.preference.m.a(SharedPreferencesCompat.java:39)
 	at net.xpece.android.support.preference.m.b(SharedPreferencesCompat.java:52)
 	at org.json.JSONArray.(JSONArray.java:108)
 	at org.json.JSONArray.(JSONArray.java:92)
 	at org.json.JSONTokener.nextValue(JSONTokener.java:97)
 	at org.json.JSONTokener.syntaxError(JSONTokener.java:449)
 org.json.JSONException: End of input at character 0 of 

dirkam avatar Feb 28 '18 12:02 dirkam

Can you say what devices do the crashes come from (model, amdroid version)?

consp1racy avatar Feb 28 '18 20:02 consp1racy

This occurrence was on a Samsung A5 running Android 7. For the rest, you can find a screenshot attached to a previous comment.

dirkam avatar Mar 01 '18 05:03 dirkam

The stacktrace may be useful. What version of the lib were you using? I'll need to match the line numbers. Thanks

consp1racy avatar Mar 02 '18 19:03 consp1racy

1.3.2 For the MultiSelectListPreference that's all I have.

dirkam avatar Mar 03 '18 05:03 dirkam

First some background on the last error: I used to store string sets as Strings with JSON arrays on Gingerbread. When reading the preference I tried to read it as Set<String> and if it failed, fall back to parsing String as JSON array and reconstruct the Set<String> from that.

Now, wrong data is stored instead of Set<String> so it mistakenly tries to parse it as JSON array from String. The preference contained an empty string it looks. It shouldn't contain a string at all on Android 7.

A String was also stored in the SeekBarPreference.

I don't see where this comes from.

consp1racy avatar Mar 06 '18 01:03 consp1racy

Got this with the new error reporting stuff. Support lib 27.1.1 with lib 2.2.0. This one occured on an S6 Edge with Android 7.0

Couldn't read 'aMultiSelectListPreference' preference as JSON

Non-fatal Exception: org.json.JSONException: End of input at character 0 of 
       at org.json.JSONTokener.syntaxError(JSONTokener.java:449)
       at org.json.JSONTokener.nextValue(JSONTokener.java:97)
       at org.json.JSONArray.(JSONArray.java:92)
       at org.json.JSONArray.(JSONArray.java:108)
       at net.xpece.android.support.preference.SharedPreferencesCompat.getStringSetFromJson(SharedPreferencesCompat.java:66)
       at net.xpece.android.support.preference.SharedPreferencesCompat.getStringSet(SharedPreferencesCompat.java:56)
       at android.support.v7.preference.XpPreferenceCompat.getPersistedStringSet(XpPreferenceCompat.java:90)
       at android.support.v7.preference.XpPreferenceCompat.persistStringSet(XpPreferenceCompat.java:59)
       at net.xpece.android.support.preference.MultiSelectListPreference.setValues(MultiSelectListPreference.java:138)
       at net.xpece.android.support.preference.MultiSelectListPreference.onSetInitialValue(MultiSelectListPreference.java:197)
       at android.support.v7.preference.Preference.dispatchSetInitialValue(Preference.java:6519)
       at android.support.v7.preference.Preference.onAttachedToHierarchy(Preference.java:1257)
       at android.support.v7.preference.PreferenceGroup.addPreference(PreferenceGroup.java:234)
       at android.support.v7.preference.XpPreferenceInflater.android.support.v7.preference.PreferenceGroup.addItemFromInflater(XpPreferenceInflater.java:4166)
       at android.support.v7.preference.XpPreferenceInflater.rInflate(XpPreferenceInflater.java:293)
       at android.support.v7.preference.XpPreferenceInflater.rInflate(XpPreferenceInflater.java:293)
       at android.support.v7.preference.XpPreferenceInflater.rInflate(XpPreferenceInflater.java:293)
       at android.support.v7.preference.XpPreferenceInflater.rInflate(XpPreferenceInflater.java:293)
       at android.support.v7.preference.XpPreferenceInflater.inflate(XpPreferenceInflater.java:103)
       at android.support.v7.preference.PreferenceInflater.inflate$7af30e91(PreferenceInflater.java:112)
       at android.support.v7.preference.XpPreferenceManager.inflateFromResource$6154c3e6(XpPreferenceManager.java:69)
       at .SettingsFragment.android.support.v7.preference.PreferenceFragmentCompat.addPreferencesFromResource(SettingsFragment.java)
       at android.support.v7.preference.XpPreferenceFragment.onCreatePreferences(XpPreferenceFragment.java:56)
       at android.support.v7.preference.PreferenceFragmentCompat.onCreate(PreferenceFragmentCompat.java:224)
       at android.support.v4.app.Fragment.performCreate(Fragment.java:2331)
       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1386)
       at android.support.v4.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1188)
       at android.support.v4.app.FragmentTransition.calculateFragments(FragmentTransition.java:1071)
       at android.support.v4.app.FragmentTransition.startTransitions(FragmentTransition.java:115)
       at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2380)
       at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338)
       at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2245)
       at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3248)
       at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3200)
       at android.support.v4.app.FragmentActivity.android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentActivity.java:11195)
       at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:177)
       at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1256)
       at android.app.Activity.performStart(Activity.java:6959)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2890)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2988)
       at android.app.ActivityThread.-wrap14(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1631)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6682)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

dirkam avatar May 04 '18 08:05 dirkam

There are two potential issues here:

1) Reading the preference

Does your MultiSelectListPreference have a default value? Is it an empty string? If so, it should instead

  • point to an empty string array resource, or
  • be equal to @null, which is also the implicit default.

String, even an empty one, cannot be parsed as a Set<String> by the preference framework. I will make this throw as it should in the next version of the library.

2) Writing the preference

This is the non-fatal you reported in the previous comment.

I'll fix the library so it doesn't throw ClassCastException when writing preferences. Framework doesn't throw, my MultiSelectListPreference erroneously did. Thanks for catching it.

consp1racy avatar May 10 '18 22:05 consp1racy

Please try and test the current snapshot and let me know if you encounter any errors.

implementation 'com.github.consp1racy:android-support-preference:7d2c9b3fbb'

consp1racy avatar May 11 '18 21:05 consp1racy

I'll try the snapshot version, though I can't reproduce these so not sure if I'll notice anything.

I don't set a default value in XML. I set the value runtime and here it can happen that I pass a set like this without any value: Set<String> set = new HashSet<>().

dirkam avatar May 12 '18 05:05 dirkam

I have the same problem. Firebase Crashlytics Ekran Alıntısı

janvalji avatar Apr 13 '20 21:04 janvalji

just uninstall your app and then install it. look like you saved string on that key before. or change the key or clear app data then check

ammadmunir avatar Jun 05 '20 04:06 ammadmunir