TextView$SavedState cannot be cast to com.stripe.android.view.StripeEditText$StripeEditTextState
Summary
We are facing an issue since many versions ago. We have been delaying this issue as it has not been much impactful until now. We are having some spikes and we would like to come with a fix asap :)
Code to reproduce
We can't reproduce and the feedback compres from several different devices and version here is the log of one crash:
Fatal Exception: java.lang.ClassCastException: android.widget.TextView$SavedState cannot be cast to com.stripe.android.view.StripeEditText$StripeEditTextState
at com.stripe.android.view.StripeEditText.onRestoreInstanceState(StripeEditText.kt:255)
at com.stripe.android.view.CardNumberEditText.onRestoreInstanceState(CardNumberEditText.kt:323)
at android.view.View.dispatchRestoreInstanceState(View.java:22756)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at com.google.android.material.textfield.TextInputLayout.dispatchRestoreInstanceState(TextInputLayout.java:3171)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4219)
at android.view.View.restoreHierarchyState(View.java:22734)
at androidx.fragment.app.Fragment.restoreViewState(Fragment.java:699)
at androidx.fragment.app.Fragment.restoreViewState(Fragment.java:3177)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:3162)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:631)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:281)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1614)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3198)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3116)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:3163)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:631)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:281)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1614)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3198)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3116)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:350)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:251)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1510)
at android.app.Activity.performStart(Activity.java:8616)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4204)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2574)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8762)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
Android version
Impacted devices
Installation method
Gradle
Dependency Versions
kotlin: 2.0.0
stripe-android: 20.47.0
Android Gradle Plugin: 8.4.0
Gradle: gradle-8.7
SDK classes
N/A
Video
Other information
Ping, is there anyone who could provide feedback?
Hey @Atternatt, can you provide more information on your integration or steps to reproduce?
hello @tjclawson-stripe the issue is the this is the only information we can provide. We, devs, are unable to reproduce but the issue is appearing quite a lot of times. My feeling is that this is happening in a Android configuration change.
We've made a few fixes in the most recent release. Please upgrade and let us know if you can still reproduce this.
@jaynewstrom-stripe I was able to finally reproduce the issue. It's happening when changing from dark/light mode because
the state arriving in the onRestoreInstanceState is TextView.SavedState.
https://github.com/stripe/stripe-android/blob/c0e0e752594523cba27d42a1f954a5e376406fc9/payments-core/src/main/java/com/stripe/android/view/StripeEditText.kt#L255
Any chance you could do a nullable cast here since you already have a let? I can open a PR with that, if needed.
If you want to open a PR, and validate the fix, that would be fantastic!
Cool, will do!