Биллинговый API v3 IabHelper NullPointerException
edit 4/15: Ловля нулевого указателя в IabHelper, похоже, остановила эту проблему. Я больше не вижу исключения, которые меня бросают, я собираюсь принять это как ответ.
edit 4/04: Немного более глубокое погружение. Существуют блоки catch catch, которые обрабатывают RemoteExceptions и JSONExceptions для метода queryPurchases, но не обрабатывают NullPointerException. То, что я собираюсь попробовать, включает в себя обработку NullPointer Exception, поэтому IabHelper выглядит так, когда вы пытаетесь выполнить запросSkuDetails:
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: хорошо, все еще получая этот сбой... теперь это происходит при попытке получить контекст в строке 3 следующего отрывка из IabHelper:
int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException {
logDebug("Querying owned items, item type: " + itemType);
logDebug("Package name: " + mContext.getPackageName());
Это разочаровывает, потому что в моем манифесте я всегда использую полное имя пути моего приложения для "имени".
Пример "com.myappname.blah.ClassName"
Я также пробовал передать это, MyClass.this, getApplicationContext() в mHelper. Однако все они производят одинаковые результаты NullPointer случайным образом с устройств в дикой природе. Я также попробовал name= "MyClass" в манифесте. Это выглядит так:
mHelper = new IabHelper(MyClass.this, myKey);
edit 3/18/13: Я все еще получаю исключения, даже с новой версией IabHelper, развернутой на 3/17.
Я начинаю видеть шаблон здесь, что все сбои при попытке получить контекст при выполнении mContext.getPackageName(). Мне любопытно, почему это работает на всех моих тестовых устройствах, и я не могу воспроизвести этот сбой и, похоже, только на небольшом количестве устройств.
Вот новый сбой:
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());
edit 3/17/13: я вижу, что за последние несколько месяцев было опубликовано множество исправлений об ошибках, я попробую последний код, доступный здесь, и посмотреть, устраняет ли это проблему:
https://code.google.com/p/marketbilling/source/browse/v3/src/com/example/android/trivialdrivesample/util
В одном из моих приложений я использую API биллинга и код шаблона, включенный в него.
Я использую последнюю версию биллингового API, доступную через менеджер SDK по состоянию на 3/16/2013.
В моей деятельности я запрашиваю инвентарь, используя следующее:
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);
}
}
}
Я получаю несколько отчетов NullPointerException в дикой природе из класса IabHelper для следующих устройств. Я не могу воспроизвести проблему и не могу найти никакой информации об этих авариях, и именно поэтому я публикую этот вопрос.
У меня есть множество других проверок для значений NULL и блоков try/catch в стороне разработчика, связанной с биллинговым API, в том числе внутри onQueryInventoryFinished, поэтому я знаю, что это исключение не выбрасывается из "моего кода" (потому что я не снимая сбоев с любого из моих классов приложений), но вместо этого вызывается из самого IabHelper. Я не изменил IabHelper, кроме этого рекомендуемого исправления: qaru.site/info/106482/...
Crash # 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);
Crash # 2 Samsung 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);
Ответы
Ответ 1
edit 4/15: Ловля нулевого указателя в IabHelper, похоже, остановила эту проблему. Я больше не вижу исключения, которые меня бросают, я собираюсь принять это как ответ.
edit 4/04: Немного более глубокое погружение. Существуют блоки catch catch, которые обрабатывают RemoteExceptions и JSONExceptions для метода queryPurchases, но не обрабатывают NullPointerException. То, что я собираюсь попробовать, включает в себя обработку NullPointer Exception, поэтому IabHelper выглядит так, когда вы пытаетесь выполнить запросSkuDetails:
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);
}
}
Ответ 2
Возможно, вы используете асинхронные операции. Текущий IabHelper небезопасен, если вы используете методы... async. Проблема в том, что в любой момент запускается асинхронная операция. Dispose может быть вызван в основном потоке. В этом случае вы получите 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
Ответ 3
Немного измените начало метода 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, чтобы указать причину этого.
Ответ 4
tmanthey patch также требует
mDisposeRequested = false;
после проведения распоряжения
Ответ 5
IabHelper устарел и был заменен BillingClient.
См. https://developer.android.com/google/play/billing/billing_library.html
Ответ 6
Если вы получаете эту ошибку на эмуляторе, это может быть очень простая вещь, которая случается в более чем половине случаев.
Убедитесь, что вы используете Google API SDK, а не обычный SDK.