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?
Related
I have a repository making a network call via a datasource.
I have two use cases that both call that reposository to get the resource but are making different treatments.
Those use cases are subscribing at the same time.
The behavior I want is to make the network call on first subscription, block the other ones and then cache the data to observers in queue.
For now I have a fetch method in the repository actually making the network call (called at one place in my code). I have a get method that return a behavior subject that is valued when the fetch method get data (the uses cases are observing this behavior subject).
I don't like having those two methods and I think it should be transparent. In an ideal case the use cases should call a single repository method and get data (the first one making the network call because cache is missing, the second one getting the cached data).
Is there a way to do this with RxJava ?
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'm using the post-Google I/O 2016 Firebase database.
On a DatabaseReference, there is two similar methods, seem to only differ by the completion callback.
One is void setValue(Object value, DatabaseReference.CompletionListener listener), and another is Task<Void> setValue(Object value).
Are they interchangeable? The docs does not say anything about it and the Firebase Android SDK is closed source.
They are almost interchangeable. The key difference between the Task returned by setValue and the passed CompletionListener is the ability to avoid object leaks.
When you pass a CompletionListener to setValue, the Firebase SDK will hold on to that object reference (and all of that object's strong references, and so on) indefinitely, until the data is finally written at the server side. For Android apps, this can be particularly problematic because you could end up leaking an Activity reference, which is pretty expensive.
When you use a Task, you have the ability to add and remove listeners from that as needed, so if you're no longer interested in knowing if a write succeeded, you can free up the objects that were previously interested. In Android, there are overloads for adding listeners that automatically let a listener remove itself when the activity is stopped, so you don't have to arrange to do that yourself.
With Tasks, you can also arrange to have your callback invoked on a particular Executor, which is a convenient way to kick intense work off to another thread. With, CompletionListener, you'd have to arrange for that yourself in the callback itself.
I have a four-part blog series on the Tasks that are provided by Play services and the Java admin SDK. There is also formal documentation.
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.
I'm having trouble figuring out how the in-app billing process is supposed to work for broadcast events when the application isn't running. I have a managed product setup and as far as I can see, is working well. With a test account I'm able to purchase my published component and my test application handles it, retaining its state. I then cancel this order via my merchant account and the application again receives the event and removes the item.
The problem occurs when instead of cancelling the order while the application is active. I exit out of it (not with home, with multiple back buttons). If I cancel the item now, my 'device' gets a notification 'purchase failed', but when I start my application nothing seems to happen and thus the state of the item is still purchased.
I'm not sure if billing service is still running or not. Given the documentation says my application must send back a CONFIRM_NOTIFICATIONS or it keeps sending it I can only assume it is. However why is it unable to interact with my database and remove the item like it does correctly if the application is active?
I hope tihs is clear, and I apologize if it has been discussed before, I couldn't find anything in my searches.
Apologies for answering my own question but hopefully my findings will help others that were confused as I was.
My issue was thinking that the Dungeons.java class provided in the example had all the code needed for modification. The example design has its database implementation nested in the observer class that is active while the user is interacting with the store. The issue it created for me outlined in my question, what happens if a transaction is cancelled after the fact when this observer isn't registered or the application isn't running.
From trial and error my solution was to take the database interaction out of the observer and place it in
private void purchaseStateChanged(int startId, String signedData, String signature) {
of the BillingService class.
Placed in here, when my broadcast receiver fires, I act on a cancellation and update my database accordingly regardless of whether my application is started much less my observer registered.