Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] "PaymentOptionsViewModel should already exist" when using PaymentSheet.FlowController #8458

Open
alabrecq opened this issue May 13, 2024 · 2 comments
Labels

Comments

@alabrecq
Copy link

Summary

When we use PaymentSheet.FlowController in our app, presented from a Fragment for a purchase flow, if the user backgrounds the app after the payment sheet is presented and then comes back to the app later after the host Activity has been destroyed (but the process is still in memory), we receive this crash:

com.stripe.android.paymentsheet.ui.PaymentOptionsPrimaryButtonContainerFragment$viewModel$2$1 in invoke at line 79
com.stripe.android.paymentsheet.ui.PaymentOptionsPrimaryButtonContainerFragment$viewModel$2$1 in invoke
com.stripe.android.paymentsheet.PaymentOptionsViewModel$Factory in create at line 323
androidx.lifecycle.ViewModelProvider in get at line 187
androidx.lifecycle.ViewModelProvider in get at line 153
androidx.lifecycle.ViewModelLazy in getValue
androidx.lifecycle.ViewModelLazy in getValue at line 53
androidx.lifecycle.ViewModelLazy in getValue
com.stripe.android.paymentsheet.ui.PaymentOptionsPrimaryButtonContainerFragment in getViewModel
1
com.stripe.android.paymentsheet.ui.BasePrimaryButtonContainerFragment in setupPrimaryButton
com.stripe.android.paymentsheet.ui.BasePrimaryButtonContainerFragment in setupPrimaryButton at line 49
com.stripe.android.paymentsheet.ui.BasePrimaryButtonContainerFragment in onViewCreated at line 36
androidx.fragment.app.Fragment in performViewCreated
androidx.fragment.app.FragmentStateManager in createView
androidx.fragment.app.FragmentStateManager in createView at line 552
androidx.fragment.app.FragmentStateManager in moveToExpectedState
androidx.fragment.app.FragmentStateManager in moveToExpectedState at line 261
androidx.fragment.app.FragmentStore in moveToExpectedState
androidx.fragment.app.FragmentStore in moveToExpectedState at line 113
androidx.fragment.app.FragmentManager in moveToState
androidx.fragment.app.FragmentManager in moveToState at line 1433
androidx.fragment.app.FragmentManager in dispatchStateChange at line 2977
androidx.fragment.app.FragmentManager in dispatchActivityCreated at line 2895
androidx.fragment.app.FragmentController in dispatchActivityCreated
androidx.fragment.app.FragmentActivity in onStart
androidx.fragment.app.FragmentActivity in onStart at line 351
androidx.appcompat.app.AppCompatActivity in onStart
android.app.Instrumentation in callActivityOnStart at line 1457
android.app.Activity in performStart at line 8259
android.app.ActivityThread in handleStartActivity at line 3776
android.app.servertransaction.TransactionExecutor in performLifecycleSequence at line 221
android.app.servertransaction.TransactionExecutor in cycleToPath at line 201
android.app.servertransaction.TransactionExecutor in executeLifecycleState at line 173
android.app.servertransaction.TransactionExecutor in execute at line 97
android.app.ActivityThread$H in handleMessage at line 2311
android.os.Handler in dispatchMessage at line 111
android.os.Looper in loopOnce at line 238
android.os.Looper in loop at line 357
android.app.ActivityThread in main at line 8090
java.lang.reflect.Method in invoke
com.android.internal.os.RuntimeInit$MethodAndArgsCaller in run at line 548
com.android.internal.os.ZygoteInit in main at line 1026

This flow can be more easily reproduced with the developer option "Don't Keep Activities" turned on on the device or emulator. I think that this helps simulate the lifecycle flow for an app when the user goes away from it and then returns after the Android system has decided to reclaim resources by removing the cached Activity from memory.

Code to reproduce

Payment sheet creation is pretty straightforward using FlowController:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    paymentFlowController = PaymentSheet.FlowController.create(
        fragment = this,
        { paymentOption -> /* */ },
        { result -> /* */ }
    )
    /* */
}
private fun configurePaymentSheet(clientSecret: String) {
    paymentFlowController.configureWithPaymentIntent(
        clientSecret,
        PaymentSheet.Configuration(
            merchantDisplayName = /* */,
            primaryButtonLabel = /* */,
            allowsDelayedPaymentMethods = true,
            appearance = PaymentSheet.Appearance(
                /* */
            )
        ),
    ) { isReady, error ->
        /* Enables access to payment sheet via clickPaymentMethod */
    }
}
private fun clickPaymentMethod() {
    paymentFlowController.presentPaymentOptions()
}

After the payment sheet has been shown on screen, you reproduce the crash by backgrounding the app and then returning to it later.

As long as the host Activity instance remains in memory, everything works as expected and the user returns to the payment sheet.

In the case where the system has destroyed the Activity to reclaim memory, a crash occurs and the user doesn't return to the payment sheet. Again, "Don't Keep Activities" seems to help to produce this scenario easily.

Android version

Across all versions of Android.

Impacted devices

None in particular.

Installation method

Through the Gradle dependency.

Dependency Versions

kotlin: 1.9.0
stripe-android: 20.42.0
Android Gradle Plugin: 8.1.1
Gradle: 8

SDK classes

PaymentSheet.FlowController

@alabrecq alabrecq added the bug label May 13, 2024
@jaynewstrom-stripe
Copy link
Collaborator

Does this still happen if you move the creation of flow controller to onCreate?

@alabrecq
Copy link
Author

Good idea. I tried this out but have had the same result unfortunately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants