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

Use lifecycleScope where possible in Stripe.kt #3567

Merged
merged 6 commits into from
Apr 26, 2021

Conversation

mshafrir-stripe
Copy link
Collaborator

Summary

  • Use lifecycleScope where possible.
  • Make some PaymentController methods suspend. This will help with
    potential memory leaks caused by StripePaymentController.
  • Inject uiContext to StripePaymentController.

Motivation

Make StripePaymentController lifecycle-aware.

Testing

  • Added tests
  • Modified tests
  • Manually verified

- Use `lifecycleScope` where possible.
- Make some `PaymentController` methods `suspend`. This will help with
  potential memory leaks caused by `StripePaymentController`.
- Inject `uiContext` to `StripePaymentController`.
Copy link

@ebarrenechea-stripe ebarrenechea-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good! Just a couple of questions about lifecycle and coroutine context.

activity: Activity
): CoroutineScope = when (activity) {
is ComponentActivity -> activity.lifecycleScope
else -> MainScope()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this else branch is an edge case. MainScope is a very sensible fallback here but it lacks knowledge about the component's lifecycle. The coroutine will continue to execute (and hold a strong reference to the activity) even after the activity finishes. I think a lifecycle observer wrapper would be a good option here but that will also depend on min SDK version and/or if we're using the androidx libraries. At the end of the day, I feel like this might be just a poor back-port of the ComponentActivity approach. Is there any data on how many of our users are still using the plain Activity vs its support lib/androidx counterparts?

In any case, MainScope will do fine here but might result in leaking activities in apps using old code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this isn't ideal and mainly an attempt to make things better for users using ComponentActivity subclasses without introducing a breaking API change (will consider doing that in a future PR).

It might actually make sense to use Dispatchers.IO as the fallback, which is the existing behavior.

@@ -73,7 +73,8 @@ internal class StripePaymentController internal constructor(
private val paymentRelayLauncher: ActivityResultLauncher<PaymentRelayStarter.Args>? = null,
private val paymentAuthWebViewLauncher: ActivityResultLauncher<PaymentAuthWebViewContract.Args>? = null,
private val stripe3ds2ChallengeLauncher: ActivityResultLauncher<PaymentFlowResult.Unvalidated>? = null,
private val workContext: CoroutineContext = Dispatchers.IO
private val workContext: CoroutineContext = Dispatchers.IO,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to specify a work context here?Could we get away with just specifying the ui context and delegating actual context switch to the components implementing the suspend functions?

Edit: I had a quick look at the code for some of our dependencies and we're injecting the work context into DefaultStripeChallengeStatusReceiver. This seems like the only place where we would "need" a work context. There are ways around this requirement, though and maybe something we can address in a different PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right. I'll take a look at this in a follow-up PR.

@ccen-stripe ccen-stripe removed their assignment Apr 22, 2021
ccen-stripe
ccen-stripe previously approved these changes Apr 23, 2021
@mshafrir-stripe mshafrir-stripe merged commit 28fba5f into master Apr 26, 2021
@mshafrir-stripe mshafrir-stripe deleted the stripe-lifecycle-scope branch April 26, 2021 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants