计费API v3 IabHelper NullPointerException

编辑4/15:在IabHelper中捕获空指针似乎已经停止了此问题。 我不再看到exception被抛出,我将接受这个答案。


编辑4/04:稍微深入一点。 有tryPatch块为queryPurchases方法处理RemoteExceptions和JSONExceptions,但没有NullPointerException处理。 我要去尝试的是包括空指针exception处理,所以当试图查询时,IabHelper看起来像这样:

catch (NullPointerException e) { throw new IabException(IABHELPER_UNKNOWN_ERROR, "NullPointer while refreshing inventory.", e); } 

我刚刚提交了一个错误:

https://code.google.com/p/marketbilling/issues/detail?id=114


编辑3/25:好吧,仍然收到这个崩溃…现在它发生,试图从IabHelper以下摘录的第3行获取上下文:

 int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException { logDebug("Querying owned items, item type: " + itemType); logDebug("Package name: " + mContext.getPackageName()); 

这是令人沮丧的,因为在我的清单中,我总是使用我的应用程序的完整path名称“名称”。

示例“com.myappname.blah.ClassName”

我也试着把这个,MyClass.this,getApplicationContext()传给mHelper。 然而,它们都会从野外的设备中随机产生相同的NullPointer结果。 我也在清单中试过name =“。MyClass”。 这就是目前的情况:

 mHelper = new IabHelper(MyClass.this, myKey); 

编辑 3/18/13:即使在3月17日部署了新的IabHelper版本,我仍然收到exception。

我开始在这里看到一个模式,当执行mContext.getPackageName()时试图获得一个上下文时崩溃都是。 我很好奇为什么在我所有的testing设备上都能正常工作,而且我不能重现这个崩溃,而且似乎只能在less量设备上运行。

这是新的崩溃:

 java.lang.NullPointerException at com.myapp.util.IabHelper.queryPurchases(SourceFile:836) at com.myapp.util.IabHelper.queryInventory(SourceFile:558) at com.myapp.util.IabHelper.queryInventory(SourceFile:522) at com.myapp.util.IabHelper$2.run(SourceFile:617) at java.lang.Thread.run(Thread.java:1019) 

引起IabHelper …

 line 836: logDebug("Package name: " + mContext.getPackageName()); 

编辑 3/17/13:我看到过去几个月发布了很多错误修复,我会尝试使用最新的代码,看看是否可以解决这个问题:

https://code.google.com/p/marketbilling/source/browse/v3/src/com/example/android/trivialdrivesample/util


在我的一个应用程序中,我使用了结算API和随附的样板代码。

截至2013年3月16日,我正在使用SDKpipe理器提供的最新版本的结算API。

在我的活动中,我使用以下查询库存:

 final List<String> skuList = new ArrayList<String>(); skuList.add("sku1"); skuList.add("sku2"); skuList.add("sku3"); if (skuList != null) { if (skuList.size() > 0) { try { mHelper.queryInventoryAsync(true, skuList, mGotInventoryListener); } catch (Exception e) { ACRA.getErrorReporter().handleException(e); } } } 

我从以下设备的IabHelper类中得到了多个NullPointerException报告。 我不能重现这个问题,也找不到有关这些崩溃的任何信息,这就是我发布这个问题的原因。

我在结算API的“面向开发人员”部分(包括onQueryInventoryFinished)中有无数个其他的检查nulls和try / catch块,所以我知道这个exception不是从“我的代码”抛出(因为我没有捕获崩溃从我的任何应用程序的类),而是从IabHelper本身抛出。 我没有修改IabHelper比这个build议的修复程序: https ://stackoverflow.com/a/14737699

崩溃#1 Galaxy Nexus

 java.lang.NullPointerException at com.myapp.util.IabHelper.querySkuDetails(SourceFile:802) at com.myapp.util.IabHelper.queryInventory(SourceFile:471) at com.myapp.util.IabHelper$2.run(SourceFile:521) at java.lang.Thread.run(Thread.java:856) 

引起IabHelper …

 line 802: Bundle skuDetails = mService.getSkuDetails(3, mContext.getPackageName(), ITEM_TYPE_INAPP, querySkus); 

碰撞#2三星GT-S5570L

 java.lang.NullPointerException at com.myapp.util.IabHelper.queryPurchases(SourceFile:735) at com.myapp.util.IabHelper.queryInventory(SourceFile:465) at com.myapp.util.IabHelper$2.run(SourceFile:521) at java.lang.Thread.run(Thread.java:1019) 

引起IabHelper …

 line 735: Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(), ITEM_TYPE_INAPP, continueToken); 

编辑4/15:捕获在IabHelper中的空指针似乎已经停止了这个问题。 我不再看到exception被抛出,我将接受这个答案。


编辑4/04:稍微深入一点。 有tryPatch块为queryPurchases方法处理RemoteExceptions和JSONExceptions,但没有NullPointerException处理。 我要去尝试的是包括空指针exception处理,所以当试图查询时,IabHelper看起来像这样:

  catch (NullPointerException e) { throw new IabException(IABHELPER_UNKNOWN_ERROR, "NullPointer while refreshing inventory.", e); } 

我刚刚提交了一个错误:

https://code.google.com/p/marketbilling/issues/detail?id=114


更改

  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)."); } } 

  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); } } 

更改

  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)."); } } 

  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); } } 

您可能正在使用asynchronous操作。 目前的IabHelper是不安全的,如果你使用…asynchronous方法。 问题是在任何时候asynchronous操作正在运行处理可以在主线程上调用。 在这种情况下,你将得到NullPointerExceptions和IllegalStateExceptions。

这是修补它的补丁:

 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(); } 

或者在这里下载补丁。 http://code.google.com/p/marketbilling/issues/detail?id=139&thanks=139&ts=1375614409

稍微修改queryPurchases方法的开头,如下所示:

 int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException { // Query purchases //logDebug("Querying owned items, item type: " + itemType); //logDebug("Package name: " + mContext.getPackageName()); boolean verificationFailed = false; String continueToken = null; do { // logDebug("Calling getPurchases with continuation token: " + continueToken); if(mDisposed || mService==null) return IABHELPER_UNKNOWN_ERROR; Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(), itemType, continueToken); 

感谢sebastie指出这个原因。

tmanthey 补丁也需要

 mDisposeRequested = false; 

处理发生后

IabHelper已经过时,并已被BillingClient取代。 请参阅https://developer.android.com/google/play/billing/billing_library.html

如果你在模拟器上得到这个错误,这可能是一个非常简单的事情发生在一半以上的情况。

检查您使用的是Google API SDK而不是正规的SDK!