Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Pay AutoResolveHelper.resolveTask() not calling onActivityResult in Fragment

I have implemented Google Pay in app and making paymentData request I am using AutoResolveHelper to display bottom sheet and than get results via onActivityResult. I am making this request from Fragment not from Activity. So I am passing parent activity like this.

 paymentsClient?.loadPaymentData(gpayViewModel.paymentDataRequest)?.let { task ->
            AutoResolveHelper.resolveTask(task, requireActivity(), LOAD_PAYMENT_DATA_REQUEST_CODE)
        }

the problem is that this AutoResolveHelper is not calling onActivityResult on Fragment but only on Activity.

I have read something like this:

If you're calling startActivityForResult() from the fragment then you should call startActivityForResult(), not getActivity().startActivityForResult(), as it will result in fragment onActivityResult().

So it suggest that when AutoResolveHelper is calling startActivityForResult() on passed activity then fragment's onActivityResult will never be called.

So now my only option is to implement onActivityResult in Activity and somehow pass control from this Activity to my child Fragment but this need some boilerplate code and as my Fragment is Reusable than this solution is not perfect.

Meanwhile I have spotted that this code startActivityForResult in correct way and than the Fragment's onActivityResult is called correctly:

 val intent = Intent(activity, CardIOActivity::class.java)
        intent.putExtra(CardIOActivity.EXTRA_REQUIRE_EXPIRY, true)
        intent.putExtra(CardIOActivity.EXTRA_REQUIRE_CVV, true)
        intent.putExtra(CardIOActivity.EXTRA_REQUIRE_CARDHOLDER_NAME, true)

        startActivityForResult(intent, CARD_IO_REQUEST_CODE)

So can I replace this AutoResolveHelper.resolveTask() somehow to execute this task in such way that onActivityResult will not be necessary or I could startActivityForResult myself?

like image 437
Michał Ziobro Avatar asked Jan 03 '19 10:01

Michał Ziobro


1 Answers

As of today, the receipt of a result is bound to the Activity. Part of the reason for that is that the library is not precisely using startActivityForResult to initiate this process; and Fragment support on that same functionality is at the moment limited.

There are basically two ways to circumvent this at the moment (these have been shared in other threads too). However, I personally feel that mixing responsibilities between the fragment and the activity does not provide for great code clarity and clear logic, so as of now, I'd only consider an approach where the activity is responsible for making the call to AutoResolveHelper, capturing the result and sharing it with the fragment. Instead of calling the activity from the fragment, I'd consider doing that through a contract / interface in order to reduce the level of coupling between the two.

A simplistic example could be something like:

interface PaymentsContract {
    fun loadPaymentData(request: PaymentDataRequest, requestCode: Int)
}

Having the activity implement it, and passing it as a reference to the fragment at construction time allows your fragment to stay reusable and agnostic from the activity.

Once the result is ready, you can choose to find the fragment in question and propagate the onActivityResult method to it, or alternatively use a similar contract-based approach for the fragment too.

It'd be useful to learn more about your concrete use cases in order to better understand the rationale to handle this logic within fragments, and ultimately take that feedback back to the team to be considered for future developments.

Hope this is useful.

EDIT: Another alternative to interfaces is to use lambda expressions to let your fragment know about a callable that was defined somewhere else (eg.: in your activity), and that needs to be called when something happens (eg.: when your user hits the "Pay with Google Pay" button).

like image 89
Jose L Ugia Avatar answered Nov 10 '22 20:11

Jose L Ugia