stripe-react-native
stripe-react-native copied to clipboard
Fragments shouldn't have variables in default constructor
Describe the bug
In both GooglePayFragment
and PaymentSheetFragment
we create a fragment and inject variables in the constructor. This is considered a bad practice and can lead to undesired side effects. Reason for having an 0 arg constructor is that Android can recreate the fragment itself when config changes.
See this link for a good explanation of the issue
To Reproduce We got issues in our library that the app crashes randomly when users put the app in the background. See: https://github.com/flutter-stripe/flutter_stripe/issues/996.
Reproduction is hard some could reproduce it like:
- Enable "Don't keep activities" in Developer Options.
- After calling Stripe.instance.initPaymentSheet(...) somewhere, put the app in background.
- Re-enter the app. Result: The app crashes after splash with the following stacktrace:
E/AndroidRuntime( 1575): java.lang.RuntimeException: Unable to start activity ...
androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.reactnativestripesdk.PaymentSheetFragment: could not find Fragment constructor
E/AndroidRuntime( 1575): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4166)
E/AndroidRuntime( 1575): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4312)
E/AndroidRuntime( 1575): at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
E/AndroidRuntime( 1575): at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
E/AndroidRuntime( 1575): at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
E/AndroidRuntime( 1575): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2571)
E/AndroidRuntime( 1575): at android.os.Handler.dispatchMessage(Handler.java:106)
E/AndroidRuntime( 1575): at android.os.Looper.loopOnce(Looper.java:226)
E/AndroidRuntime( 1575): at android.os.Looper.loop(Looper.java:313)
E/AndroidRuntime( 1575): at android.app.ActivityThread.main(ActivityThread.java:8741)
E/AndroidRuntime( 1575): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime( 1575): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
E/AndroidRuntime( 1575): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
E/AndroidRuntime( 1575): Caused by: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.reactnativestripesdk.PaymentSheetFragment: could not find Fragment constructor
E/AndroidRuntime( 1575): at androidx.fragment.app.Fragment.instantiate(Fragment.java:678)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentContainer.instantiate(FragmentContainer.java:57)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentManager$3.instantiate(FragmentManager.java:507)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentState.instantiate(FragmentState.java:81)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentStateManager.<init>(FragmentStateManager.java:85)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentManager.restoreSaveStateInternal(FragmentManager.java:2505)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentManager.attachController(FragmentManager.java:2665)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentController.attachHost(FragmentController.java:117)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentActivity.lambda$init$3$androidx-fragment-app-FragmentActivity(FragmentActivity.java:140)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentActivity$$ExternalSyntheticLambda0.onContextAvailable(Unknown Source:2)
E/AndroidRuntime( 1575): at androidx.activity.contextaware.ContextAwareHelper.dispatchOnContextAvailable(ContextAwareHelper.java:99)
E/AndroidRuntime( 1575): at androidx.activity.ComponentActivity.onCreate(ComponentActivity.java:362)
E/AndroidRuntime( 1575): at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:217)
E/AndroidRuntime( 1575): at io.flutter.embedding.android.FlutterFragmentActivity.onCreate(FlutterFragmentActivity.java:279)
E/AndroidRuntime( 1575): ... 15 more
E/AndroidRuntime( 1575): Caused by: java.lang.NoSuchMethodException: com.reactnativestripesdk.PaymentSheetFragment.<init> []
E/AndroidRuntime( 1575): at java.lang.Class.getConstructor0(Class.java:2363)
E/AndroidRuntime( 1575): at java.lang.Class.getConstructor(Class.java:1759)
E/AndroidRuntime( 1575): at androidx.fragment.app.Fragment.instantiate(Fragment.java:663)
E/AndroidRuntime( 1575): ... 30 more
Expected behavior The fragments should have an empty constructor so Android can recreate it when needed.
Desktop (please complete the following information): Android
Getting lots of reports of this crash from our app in prod
Any reason this has not been fixed yet? Curious, as wee see crashes from this in our production app.