Billing API v3 IabHelper NullPointerException
Solution 1:
edit 4/15: Catching nullpointer in IabHelper appears to have stopped this problem. I am no longer seeing the exceptions being thrown, I'm going to accept this as an answer.
edit 4/04: A little bit of a deeper dive. There are try catch blocks that handle RemoteExceptions and JSONExceptions for the queryPurchases method, but no NullPointerException handling. What I am going to try is include NullPointer Exception handling so IabHelper looks like this when trying to querySkuDetails:
catch (NullPointerException e) {
throw new IabException(IABHELPER_UNKNOWN_ERROR, "NullPointer while refreshing inventory.", e);
}
I just filed a bug on this:
https://code.google.com/p/marketbilling/issues/detail?id=114
Change
if (querySkuDetails) {
r = querySkuDetails(ITEM_TYPE_INAPP, inv, moreItemSkus);
if (r != BILLING_RESPONSE_RESULT_OK) {
throw new IabException(r, "Error refreshing inventory (querying prices of items).");
}
}
to
if (querySkuDetails) {
try {
r = querySkuDetails(ITEM_TYPE_INAPP, inv, moreItemSkus);
if (r != BILLING_RESPONSE_RESULT_OK) {
throw new IabException(r, "Error refreshing inventory (querying prices of items).");
}
} catch (NullPointerException e) {
throw new IabException(IABHELPER_UNKNOWN_ERROR, "NPE while refreshing inventory.", e);
}
}
Change
if (querySkuDetails) {
r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreSubsSkus);
if (r != BILLING_RESPONSE_RESULT_OK) {
throw new IabException(r, "Error refreshing inventory (querying prices of subscriptions).");
}
}
to
if (querySkuDetails) {
try {
r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreSubsSkus);
if (r != BILLING_RESPONSE_RESULT_OK) {
throw new IabException(r, "Error refreshing inventory (querying prices of subscriptions).");
}
} catch (NullPointerException e) {
throw new IabException(IABHELPER_UNKNOWN_ERROR, "NPE while refreshing inventory.", e);
}
}
Solution 2:
You are probably using async operations. The current IabHelper is not safe in case you use the ...async methods. The problem is that in any moment an async operation is running dispose can be called on the main thread. In this case you will get NullPointerExceptions and IllegalStateExceptions.
Here is the patch fixing it:
Index: src/com/evotegra/aCoDriver/iabUtil/IabHelper.java
===================================================================
--- src/com/evotegra/aCoDriver/iabUtil/IabHelper.java (revision 1162)
+++ src/com/evotegra/aCoDriver/iabUtil/IabHelper.java (working copy)
@@ -86,7 +86,10 @@
// Is an asynchronous operation in progress?
// (only one at a time can be in progress)
- boolean mAsyncInProgress = false;
+ volatile boolean mAsyncInProgress = false;
+
+ // is set to true if dispose is called while a thread is running. Allows graceful shutdown
+ volatile boolean mDisposeRequested = false;
// (for logging/debugging)
// if mAsyncInProgress == true, what asynchronous operation is in progress?
@@ -285,6 +288,12 @@
* disposed of, it can't be used again.
*/
public void dispose() {
+ // do not dispose while an async Thread is running. Will cause all kinds of exceptions.
+ // In this case dispose must be called from thread after setting mAsyncInProgress to true
+ if (mAsyncInProgress) {
+ mDisposeRequested = true;
+ return;
+ }
logDebug("Disposing.");
mSetupDone = false;
if (mServiceConn != null) {
@@ -827,6 +836,7 @@
logDebug("Ending async operation: " + mAsyncOperation);
mAsyncOperation = "";
mAsyncInProgress = false;
+ if (mDisposeRequested) IabHelper.this.dispose();
}
Or download the patch here. http://code.google.com/p/marketbilling/issues/detail?id=139&thanks=139&ts=1375614409