Android in-app billing: Can't start async oper

2019-01-16 03:20发布

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?

19条回答
Deceive 欺骗
2楼-- · 2019-01-16 03:27

Another major issue with the IabHelpr class is the poor choice of throwing RuntimeExcptions (IllegalStateException) in multiple methods. Throwing RuntimeExeptions from your own code in most cases is not desirable due to the fact that they are unchecked exceptions. That is like sabotaging your own application- if not caught, these exceptions will bubble up and crash your app.

The solution to this is to implement your own checked exception and change the IabHelper class to throw it, instead of the IllegalStateException. That will force you to handle this exception everywhere it could be thrown in your code at compile time.

Here is my custom exception:

public class MyIllegalStateException extends Exception {

    private static final long serialVersionUID = 1L;

    //Parameterless Constructor
    public MyIllegalStateException() {}

    //Constructor that accepts a message
    public MyIllegalStateException(String message)
    {
       super(message);
    }
}

Once we make the changes in the IabHelper class, we can handle our checked exception in our code where we call the class methods. For example:

try {
   setUpBilling(targetActivityInstance.allData.getAll());
} catch (MyIllegalStateException ex) {
    ex.printStackTrace();
}
查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-01-16 03:29

My solution is simple

1.) Make the mAsyncInProgress variable visible outside of IabHelper

public boolean isAsyncInProgress() {
    return mAsyncInProgress;
}

2.) Use this in your Activity like:

...
if (mIabHelper.AsyncInProgress()) return;
mIabHelper.queryInventoryAsync(...);
...
查看更多
叼着烟拽天下
4楼-- · 2019-01-16 03:29

A simple trick that did it for me was to create a method in IabHelper:

public Boolean getAsyncInProgress() {
    return mAsyncInProgress;
}

and then in your code, just check:

if (!mHelper.getAsyncInProgress())
    //launch purchase
else
    Log.d(TAG, "Async in progress already..)
查看更多
Deceive 欺骗
5楼-- · 2019-01-16 03:32

A simple tricky solution

before calling purchaseItem method just add this line

  if (billingHelper != null) billingHelper.flagEndAsync();

so your code looks this way

 if (billingHelper != null) billingHelper.flagEndAsync();
 purchaseItem("android.test.purchased");

Note: don't forget to make public flagEndAsync() method in IabHelper if you call it from another package.

查看更多
啃猪蹄的小仙女
6楼-- · 2019-01-16 03:32

I was having the same issue until I stumbled upon another SO thread. I'm including a touched up version of the code found in the other thread that you need to include in your Activity that initialises the purchase.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    // Pass on the activity result to the helper for handling
    // NOTE: handleActivityResult() will update the state of the helper,
    // allowing you to make further calls without having it exception on you
    if (billingHelper.handleActivityResult(requestCode, resultCode, data)) {
        Log.d(TAG, "onActivityResult handled by IABUtil.");
        handlePurchaseResult(requestCode, resultCode, data);
        return;
    }

    // What you would normally do
    // ...
}
查看更多
兄弟一词,经得起流年.
7楼-- · 2019-01-16 03:33

I had the same issue and the problem was that I didn't implement the method onActivityResult.

@Override
protected void onActivityResult(int requestCode,
            int resultCode,
            Intent data)
{
    try
    {
        if (billingHelper == null)
        {
            return;
        } else if (!billingHelper.handleActivityResult(requestCode, resultCode, data))
        {
            super.onActivityResult(requestCode, resultCode, data);
        }
    } catch (Exception exception)
    {
        super.onActivityResult(requestCode, resultCode, data);
    }
}
查看更多
登录 后发表回答