I have an app that has implemented In App Billing for a premium version of my app. On startup, I check if the user has purchased the product using IabHelper. When I load up my next activity, I need to check for the purchase again to decide whether or not to show certain menu content. I do not want to store the result of the call at startup in preferences or local db for security reasons and understand the Play information is cached anyway. Is my best option in the second activity to create a new instance of IabHelper and call startSetup() again then queryInventoryAsync()? Trouble with this is, as the call is asynchronous, I'm not sure when the response will return in order to update the UI menu.
This is what I'm currently doing as well. I use the async callback to update a previously held menu object to show/hide a purchase option which in reality is never seen the speed of the returned call.
To speed up the process if you call queryInventoryAsync(false, mGotInventoryListener); (note the false flag) then you will only use a local cached inventory which is far quicker to respond.
Related
I am restructuring my code to use ActivityResultContracts, and I've been able to recreate the old way of doing things with onActivityResult by passing in "codes" with my Intents and just passing them back from the called activity. Everything is working fine, but how would I manage to do that with App Updates, even the Google documentation is still using onActivityResult to check for app updates.
After looking at it for the past few days, it does not seem like it is possible to forgo using onActivityResult; the cancel response is only returned to that method. If you have a listener setup to check for resumed downloads, you will get a response there (as onResume is called when the calling activity is moved back to the foreground) but you only get that an update is available and the install status is unknown (which coincidentally is the same value as cancelled, and you can't do anything there as you get the same values on the initial call to check for an update). I don't see the point in deprecating a method you're still required to use, but oh well.
I am very new to Cloud Firestore and have some doubts regarding the querylistener read count. As most of the answer suggested on stack overflow that, we should attach the listener in onStart() and detach in OnStop() in the Android activity. I am building an app in which I have to attach the listener on Dashboard Activity and the user will navigate back and forth between dashboard and other activity frequently.
So,
when the user navigates to another activity the listener will be detached (onStop()) and if they come back it will be attached again (onStart()). And suppose between this, nothing has changed in documents on the server, will I still be charged for all read count even though nothing has changed on the server?
Should I keep the listener attach and detach only when the user kills the app? By doing this, I will be only charged for the document which is changed while the app is in the foreground and not the all-read count if navigates between Dashboard and other activity.
we should attach the listener in onStart() and detach in OnStop() in the Android activity
If you are attaching a listener for getting real-time updates, yes, you need to remove the listener according to the life-cycle of the activity, as explained in my answer from the following post:
How to set addSnapshotListener and remove in populateViewHolder in RecyclerView Item?
However, if you simply create a get() call, followed by addOnCompleteListener(), there is no listener that needs to be removed.
And to answer your first questions. It depends. If you are using a SnapshotListener and nothing is changed on the server, you'll always read the data from the cache. So you can go back and forth, as long as you want. But also keep in mind, that if the listener is disconnected for more than 30 minutes, you’ll be charged for reads as if we had issued a brand-new query. On the other hand, if you are using get(), you'll be charged with a number of read operation that is equal to the number of documents that you get, every time you call it, even if there is nothing changed on the server.
Why?
In order to provide up-to-date data, the Firestore SDK needs to check the online version of the documents against the cached one. That’s the reason why you are charged, regardless of what exists in the cache or if something is changed or not on the server.
To answer your second question, if you are using a SnapshotListener, you should always consider removing the listener, otherwise, your app will remain synchronized until Android OS will eventually close the app. It doesn't really matter if the app is in the foreground or in the background, if the listener stays active, you'll always be charged accordingly. You can find more info in the following article:
How to drastically reduce the number of reads when no documents are changed in Firestore?
In my application i want to let users sign in with their google account so i am using google play services. This works - they can login and logout. I also want to find out if the user is signed in the onCreate method when i pass from one activity to another. I am trying to use Google play services isSignedIn function for this but on onCreate method it always return false (because google play service trigger on onStart).
Why do I want it ?
Because, i have two login option. One is google account another is my own login panel. I want to know that is user sign in wtih google or my system or not on onCreate. So i will give direction my flow.
How can i achive this or do you have an alternative suggestion ?
Thank you for answers.
This is due to the Activity lifecycle. Every time an Activity goes into the background, it will get onStop. The Play Games API requires you to disconnect when this happens. When the Activity comes back into the foreground, it gets onStart, and then GameHelper will attempt to reestablish the connection. Until this happens, isSignedIn will return false. When the connection is restored (which should be very fast if the user had already signed in), the onSignInSucceeded callback will be called and from that point on isSignedIn will return true.
It's impossible to know, on onCreate, whether or not the sign-in will succeed. Instead, you should wait for either onSignInSucceeded or onSignInFailed. It is guaranteed that one of those two callbacks will be called shortly after the Activity comes into the foreground.
At that point, you can decide what to do, because it will be clear whether or not the user is signed in with Google+.
I am not certain how your app works but it sounds as though you may be calling GameHelper.onStop at the end of one activity when in fact you want the game to continue in another activity. I don't think you can do this (see the accepted answer here):
Google Play Game Services multiplayer with Activity switching
My app is arranged into fragments and I have one fragment which interacts with GameHelper. Therefore, once I have performed GameHelper.setup and GameHelper.onStart, I am able to call isSignedIn from any method in any fragment and get the correct response.
An alternative approach (which I have used in the past) is to save the result of isSignedIn in a boolean in shared preferences. You can then check this to determine whether the user is signed in or not.
Problem
I'm trying to implement in app billing v3, everything is working pretty nice except for one thing. After consuming or purchasing an item I do a request call to update the inventory. But the result always yields the old inventory and not the new one, with the added or removed item.
This could be expected behavior and I do have a workaround, but it's still pretty annoying.
Workaround
My work around exists out of a special "handler/wrapper" for in-app-billing. This "handler" has a simple life cycle.
1. create (new call): Creates a new IabHelper object and does some magic with the publickey
2. startUp: calls the startSetup method from the IabHelper and sets a flag when successful. If successful it makes a update inventory call.
3. close: despose the IabHelper object
The handler implements the onQueryInventoryFinished method, when this method is called and the result is success a local Inventory object is updated using the Inventory argument given with this method.
So basically the handler I made has two fields a Inventory and flag for successful setup. The handler also has a custom made interface for callbacks to an activity for example.
There are two more methods: buy and consume.
After successfully buying or consuming an item I would like to update the current inventory, but this does not work as said before.
My workaround: Remove or add the purchases manually from the local Inventory object. (this should be done in the buy or consume method.)
Better method?
Is there a better "more acceptable" way of doing this?
The official documentation says that "Your application must have a local Service to facilitate messaging between your application and Android Market."
My question is, is this is really necessary? And if yes, why?
Wouldn't it be possible to simply bind to the MarketBillingService from an Activity's onCreate method without having to creating a local service first?
Having to create a local service that forward the requests to the remote MarketBillingService just seems a bit over-complicated.
I agree that the In-App Billing example application has a number of layers to it that seem unnecessary, but the idea of using a Service to interact with Market is a good one. This is because the process is very asynchronous (and can take a good amount of time) and some events are generated outside the workflow of a user purchase.
While the user will be interacting with some Market UI while deciding whether to purchase the "item", after this process is over there is a long back-and-forth between your app and the market app to authorize and finalize the transaction, many steps delayed while Market communicates with its servers. You don't want to hold the user up and force them to wait on that Activity simply so you can complete the purchase. You want that to be in a Service so the user can move around in the app, or leave it completely for awhile, and still be able to finalize the purchase and download the appropriate purchased content without fear of your process being removed.
Also, there are many events that may come into your application if purchases are canceled or otherwise rejected that can happen LONG after the initial purchase back-and-forth, and the user may be doing something completely different or not have their phone awake at all at that time. You want to be able to handle these events without having to pop up an Activity.
Bottom line, it's a long-running background process...which is what Services were designed for.
HTH