23

I am testing my billing and I got this exception:

java.lang.IllegalStateException: Can't start async operation (launchPurchaseFlow) because another async operation(launchPurchaseFlow) is in progress.
        at utils.IabHelper.flagStartAsync(IabHelper.java:711)
        at utils.IabHelper.launchPurchaseFlow(IabHelper.java:316)
        at utils.IabHelper.launchPurchaseFlow(IabHelper.java:294)
        at com.problemio.SubscribeIntroActivity$6.onClick(SubscribeIntroActivity.java:117)
        at android.view.View.performClick(View.java:2532)
        at android.view.View$PerformClick.run(View.java:9308)
        at android.os.Handler.handleCallback(Handler.java:587)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:150)
        at android.app.ActivityThread.main(ActivityThread.java:4293)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:507)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
        at dalvik.system.NativeStart.main(Native Method)

After I ran this code:

    Button subscribe = (Button)findViewById(R.id.subscribe);
    subscribe.setOnClickListener(new Button.OnClickListener() 
    {  
       public void onClick(View v) 
       {              
           // FIRST CHECK IF THE USER IS ALREADY A SUBSCRIBER.
          mHelper.launchPurchaseFlow(SubscribeIntroActivity.this, SUBSCRIBE_SKU, RC_REQUEST, mPurchaseFinishedListener);

       }
    });   

But prior to this I ran it as a test user and with the test product id which was this: android.test.purchased and it worked. But when I changed product id to one of my own products ids, it crashed with the exception above.

Any ideas why that happened? Thanks!

Oyoyoy
  • 247
  • 3
  • 6
  • thanks, but how to reproduce this bug, can you please provide me the steps, users are reporting this, but i am unable to reproduce – Goofy Sep 17 '13 at 06:10

4 Answers4

55

The IabHelper will only allow a single asynchronous query to be executed at a time. You need to implement onActivityResult() and pass the parameters into the handleActivityResult() method of the IabHelper.

The in-app billing sample code implements the method like this:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);

    // Pass on the activity result to the helper for handling
    if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
        // not handled, so handle it ourselves (here's where you'd
        // perform any handling of activity results not related to in-app
        // billing...
        super.onActivityResult(requestCode, resultCode, data);
    }
    else {
        Log.d(TAG, "onActivityResult handled by IABUtil.");
    }
}
ashughes
  • 7,155
  • 9
  • 48
  • 54
  • thank you, yes I did not realize that was a necessary method to implement. Is there an order for when I call it? Or is it called by the system? – Oyoyoy Jan 02 '13 at 22:22
  • It is called by the system when the user returns to your activity from the purchase screen (whether they clicked the back button, completed the purchase, etc). The IabHelper will then call your `mPurchaseFinishedListener` with the result of the purchase. – ashughes Jan 02 '13 at 22:24
  • thank you. My main issue is that I get the error Item Not Found when i try to buy an item. But it worked when I used the test item like this: android.test.purchased ...would you happen to know what the issue may be? – Oyoyoy Jan 02 '13 at 22:30
  • To test purchasing a real item, you need to upload a version of your app to the developer console (but you don't need to publish it), and you have to be using the same (signed) version to test with. It also takes Google Play some time to process/propagate newly added items...so sometimes you unfortunately just need to wait. Check out http://developer.android.com/training/in-app-billing/test-iab-app.html if you haven't already. – ashughes Jan 02 '13 at 22:46
  • I just posted this question here if you want to get points for the answer: http://stackoverflow.com/questions/14130477/android-testing-billing-purchase-with-real-item-id-gives-error-item-not-found – Oyoyoy Jan 02 '13 at 22:47
  • One issue I have is that I did upload the app to the dveloper console (unpublished). But I am not sure how to put the unpublished item on the device from the console. – Oyoyoy Jan 02 '13 at 22:48
  • @Oyoyoy: if are asking how to put the unpublished app on the device, you can just use: `abd install appname.apk` – gcl1 Apr 13 '13 at 12:56
  • 8
    `onActivityResult()` didn't either solved the problem, still getting the exception when clicked purchase **second** time – Muhammad Babar May 10 '13 at 12:15
  • 1
    I'm also using the sample, and getting the same exception. The onActivityResult() call is definitely being made. – user291701 May 19 '13 at 23:14
  • 1
    i have implemented this but still i get the exception , any other solution? – Goofy Sep 17 '13 at 06:48
  • While @ashughes's answer is true there is another case when this error happens i.e. when user clicks the button twice. The solution would be either to set flag when calling `launchPurchaseFlow` and unset it in `onActivityResult` or just catch an `IllegalStateException` – defhlt Mar 01 '15 at 22:01
  • This elegant piece of code worked much better than the trivial drive or template code implementations of onActivityResult(). – Androidcoder Aug 07 '15 at 17:11
2

Just in case someone is missing the forest for the trees like I was...

I received a java.lang.IllegalStateException stack trace in the Play Developer Console which didn't provide much more than the error message... so I was stumped.

I couldn't figure out how this was happening at first because I never thought to try tapping the button that triggers IAB twice! (it looks disabled after the first tap due to an overlay that let's taps through, [sometimes]).

So, make sure your users can't tap your button twice.

David Murdoch
  • 87,823
  • 39
  • 148
  • 191
1

You are using sample code of google and in IabHelper class line 793 there is this piece of code

 if (mAsyncInProgress) throw new IllegalStateException("Can't start async operation (" +
            operation + ") because another async operation(" + mAsyncOperation + ") is in       progress.");

and when you make a purchase for first time 'mAsyncInProgress' becomes true,and until you haven't consumed your purchase it remains true ,so you need to consume your purchase. I recommend you to read all Classes in util package completely,it will help you.

after any successful purchase you need to consume it

mHelper.consumeAsync(purchase, mConsumeFinishedListener)

but sometimes the consume request fails so you need to handle your purchases every time your activity is created :

mHelper.queryInventoryAsync(mGotInventoryListener);

and try to consume your purchases in mGotInventoryListener callback.

sadegh saati
  • 1,168
  • 1
  • 13
  • 24
  • 1
    Consuming purchases is a billing model. You want to consume when you want to allow the user to re-purchase more of the same product. Here we have an issue when we issue purchase and then rotate phone (Or in this case click purchase button the second time) and new purchase request is issued while the first one is still pending. – eugene Dec 03 '14 at 00:04
0

get the latest version of the library here: https://code.google.com/p/marketbilling/source/browse/ where they fixed the problem