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

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?

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).

Here is a link to the working code. It may be not the perfect approach but it gets the work done.
https://readyandroid.wordpress.com/onactivityresult-is-not-being-called-in-fragment/

Related

Get activity instance from called activity

I have an activity containing some fragments. One of those fragments calls another activity. In this new activity I need to have an instance of the first activity. GetParent() returns null so I don't know how I can acomplish this...
MainActivity --contains--> Fragment1 --startActivity()--> SecondaryActivity
Is there some way to get the calling activity on the SecondaryActivity?
I don't think there is a good way of doing so.
It's really a bad practise to handle activity references like that, since android wouldn't be able to gc them when needed (orientation changes, lack of memory).
The best way is to pass all the data you need with Intent extras (intent that you use to start activity), and, if you need SecondActivity to return something, use Fragment1.startActivityForResult() for starting activity, and when done, use SecondActivity.setResult() to return desired result, you will need to override onActivityResult() to get the result (there are plenty tutorials about this).
If you absolutely need to hold references to something, you can use your own instance of Application class (don't forget to declare it in the manifest) to hold data for you while application is running.

Android best practices for Fragment to Activity communications

I am new to Android Fragment and trying to learn Fragment to Activity communications.
What is the better approach(best practice) in Android for Fragment to Activity communication?
Lets say I have FragmentA and ActivityA.
After my screen popups FragmentA, I would like to perform somemethod(probably UI related) in ActivityA
Here are two(pattern) possible
Solutions:
In FragmentA getActivity and cast the Activity to ActivityA and then call somemethod.
In FragmentA create an interface callback and then implement that callback in ActivityA. Then on the callback, call somemethod.
Which pattern is more common/perfer in Android development and why. Or do you have an even better way to communicate from fragment to activity in Android to share with me?
Any comments, opinions, and suggestions is highly appreciated and welcome. ^^ .
The second solution is the preferred one, because it allows your fragment to be more independent of its hosting activity.
If in the future you decide to put your fragment on a different activity, there are no changes needed on the fragment, and you will only need to implement the interface on your activity.
I'll add a third solution which is using an event bus (Otto for instance), which also works, although some might argue that it makes your code a little less readable.
First method will be a bad practice. Second method will work fine but your fragment is going to be tightly coupled with your activity.
There is one more better approach is to use some event bus library like otto
Using this you can communicate effectively with loose coupling in your activity & fragment.
Your second approach is more flexible. You might not see a huge benefit in one activity and one fragment case. If you have to use the same fragment in another activity, it will most likely break by casting your activity like that. That said, there is nothing wrong with the first approach, but it is just a little restricted.
First pattern is best when your fragment is used only by one activity.
Second approach is needed if you want your fragment to communicate with some other objects not the activity that hosts fragment. If you always want to communicate with hosting activity callback is not needed. Just create an interface and implement it on as many activities as needed. Then in your fragment cast activity returned by getActivity().
MyInterface myInteface = (MyInterface) getActivity();
myinterface.somemethod();
You can even check if activity implements needed interface(s) etc.
The interface approach works fine and is more flexible in so far as it doesn't tie your fragment to the activity directly. One thing you should also consider is how much work the activity might need to do, that is it may end up managing several fragments. This has a tendency to lead to 'fat fragments' as my question here asked when I started using them

Android Fragments: how do I save and pass data back to parent activity once the user closes the current activity?

I have a SearchFragment and a PersonFragment which are hosted by different FragmentActivitys
The user will navigate from the SearchFragment to the PersonFragment. When the user is done with the PersonFragment (such as when they press the back button), I would like to send data back to SearchFragment so it can update its UI with any changes the user made while in PersonFragment.
I read the best way to do this is in the Activity's finish() method. However, since I'm using fragments I'm not sure how to accomplish this.
You first communicate from PersonFragment to the associated activity using interface as a callback.
Then you can use intent to pass values between activities. From activity you can communicate to SearchFragment.
http://developer.android.com/training/basics/fragments/communicating.html
According to the tutorial on the Android developers site (link), you should declare a listener interface in your PersonFragment, implement it in your FragmentActivity and in that implementation, update your SearchFragment's UI.
Edit: Another approach would be to use LocalBroadcastManager, if you can package your relevant data in an Intent, this approach uses a bit less boilerplate code.
you dont need it, all you need to do is some ContentObserver that notifies you about the content changes, see ContentResolver and its methods: registerContentObserver() and notifyChange()
Ended up using EventBus for this

Are there any downsides to calling Activity.finish(), startActivity(), startActivityForResult() anywhere else besides in the Activity itself?

I have a project that I am working on that is currently calling the Activity methods just about all over the place. (eg. my CameraActivity is calling startActivityForResult() in its JpegPictureCallback, another activity is having startActivityForResult() called in one of its Views, and yet another has one of its button's onClickListeners call finish() )
I am new to Android, but some of this practice seems odd to me. Especially when I have had to explicitly give a child view or onClickListener the parent Activity just so it can call such methods. Usually when I have to go out of my way like that to make something work, there is usually a better way to do it.
Also calling startActivityForResult() in one class and having onActivityResult() returning in another class seems counter intuitive. It seems to not form a logical flow of information.
Specifically my questions are:
Is there a performance impact to calling Activities in this way?
Is this proper coding style? (Both personally, but specifically according to some well-defined guidelines i.e. Android's dev guidelines)
No there is no performance impact in calling activities this way.
Yes this is the standard coding style. Refer the link below for the coding standard.
For detailed info check : http://developer.android.com/training/basics/intents/result.html

Communication among fragment and activity

I'm implementing fragments in my app. Referring to this documentation,
there is written I should use getActivity() to access activity methods but also (in the next paragraph) I should declare an interface in the fragment and let activity implement it.
Now, the second way is used for callback methods like events, but I can also use getActivity().onSomeEventHappened(), can't I?
Could someone explain me the differences? Because I cannot see differences among them.
There is no difference in the end result if you know that getActivity() will always return the type of Activity you expect.
However using interfaces is a good practice because it decouples your Fragments from a particular implementation of an Activity. So later on in the future if you decide to use your fragments with a different activity, all you have to do is have that activity implement your fragments Interface to be alerted of any fragment events.
You should always strive to have decoupled components if you want an application that is easy to extend without side effects.
You can not always simply call getActivity().onSomeEventHappened(). Just imagine this case: You have two fragments, one with ListView and other which shows image based on listItem selected. In second fragment you cannot just call getActivity().onListItemClicked(), because your activity has no such method, but if activity implements interface and catches those event from the first fragment, then you are able to pass info about event to the second fragment and how the right image.

Categories

Resources