I am using the IabHelper
utility classes, as recommended by Google's tutorial, and I'm being hit hard by this error. Apparently IabHelper
can not run multiple async operations at the same time. I even managed to hit it by trying to start a purchase while the inventory taking was still in progress.
I have already tried to implement onActivityResult
in my main class as suggested here, but I don't even get a call to that method before the error hits. Then I found this but I have no idea where to find this flagEndAsync
method - it's not in the IabHelper
class.
Now I'm looking for a way around this (without reimplementing the whole she-bang). The only solution I can think of is to create a boolean field asyncActive
that is checked before an async task is started, and not do it if there is another task active. But that has many other problems, and doesn't work across activities. Also I'd prefer to have an async task queue up and run as soon as it's allowed to, instead of not running at all.
Any solutions for this issue?
A little-modified version of NadtheVlad's answer that works like charm
The logic is simple, just put the
launchPurchaseFlow()
thing in a method and use recursion in the catch block. You still need to makeflagEndAsync()
public from theIabHelper
class.I have same issue, but it resolved! I think you must be not run "launchPurchaseFlow" on UI thread, try to run launchPurchaseFlow on UI thread, it would be working fine!
if you code in fragment then you this code in IabHelper.java
This answer directly addresses the problem that @Wouter has seen...
It is true that
onActivityResult()
must be triggered, like many people have said. However, the bug is that Google's code isn't triggeringonActivityResult()
in certain circumstances, i.e. when you're pressing your [BUY] button twice when running the debug build of your app.Additionally, one major problem is that the user may be in a shaky environment (i.e. Bus or subway) and presses your [BUY] button twice... suddenly you've got yourself an exception !
At least Google fixed this embarrassing exception https://github.com/googlesamples/android-play-billing/commit/07b085b32a62c7981e5f3581fd743e30b9adb4ed#diff-b43848e47f8a93bca77e5ce95b1c2d66
Below is what I implemented in the same class where
IabHelper
is instantiated (for me, this is in the Application class) :My [BUY] button calls this
launchPurchaseWorkflow()
and passes the SKU and the activity the button is in (or if you're in a fragment, the enclosing activity)NOTE: be sure to make
IabHelper.flagEndAsync()
public.Hopefully, Google will improve this code in the near future; this problem is about 3 years old and it's still an ongoing problem :(
I ended up doing something similar to Kintaro. But added mHelper.flagEndAsync() to the end of the catch. The user still gets the toast but by the next time they push the purchase button, the async operation has been killed and the purchase button is ready to go again.
I have had this issue occasionally, and in my case I've tracked it down to the fact that if the onServiceConnected method in IabHelper can be called more than once if the underlying service disconnects and reconnects (e.g. due to an intermittent network connection).
The specific operations in my case were "Can't start async operation (refresh inventory) because another async operation(launchPurchaseFlow) is in progress."
The way that my app is written, I can't call launchPurchaseFlow until after I've had a completed queryInventory, and I only call queryInventory from my onIabSetupFinished handler function.
The IabHelper code will call this handler function whenever its onServiceConnected is called, which can happen more than once.
The Android documentation for onServiceDisconnected says:
which explains the problem.
Arguably, IabHelper shouldn't call the onIabSetupFinished listener function more than once, but on the other hand it was trivial to fix the problem in my app by simply not calling queryInventory from within this function if I've already done it and got the results.