edit 4/15:IabHelperでnullポインタをキャッチすると、この問題が停止したようです。例外がスローされることはもうありません。これを答えとして受け入れます。
edit 4/04:もう少し詳しく説明します。 queryPurchasesメソッドのRemoteExceptionsとJSONExceptionsを処理するtry catchブロックがありますが、NullPointerException処理はありません。私が試してみるのは、NullPointer例外処理を含めることです。そのため、querySkuDetailsを実行しようとすると、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
edit 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());
私のマニフェストでは常に「name」にアプリのフルパス名を使用しているため、これはイライラします。
例 "com.myappname.blah.ClassName"
これ、MyClass.this、getApplicationContext()をmHelperに渡してみました。ただし、それらはすべて、実際のデバイスからランダムに同じNullPointer結果を生成します。マニフェストでname = "。MyClass"も試しました。これは現在、次のようになっています。
mHelper = new IabHelper(MyClass.this, myKey);
edit3/18/13:3/17にデプロイされた新しいIabHelperバージョンを使用しても、例外が発生します。
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());
edit2013年3月17日:過去数か月にわたって多くのバグ修正が公開されているようです。ここで入手可能な最新のコードを試してみます。これで問題が解決するかどうかを確認します。
私のアプリの1つで、課金APIとそれに含まれているボイラープレートコードを使用しています。
2013年3月16日の時点で、SDKマネージャーから入手できる最新バージョンの課金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レポートを実際に受け取ります。私は問題を再現できず、これらのクラッシュに関する情報を見つけることができません。これが私がこの質問を投稿する理由です。
OnQueryInventoryFinished内を含め、課金APIの「開発者向け」部分にnullとtry/catchブロックの無数の他のチェックがあります。そのため、この例外が「コード」からスローされていないことがわかります(クラッシュをキャプチャしていないため)私のアプリのクラスのいずれかから)が、代わりにIabHelper自体からスローされています。私はこの推奨修正以外のIabHelperを変更していません: 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 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);
edit 4/15:IabHelperでnullポインタをキャッチすると、この問題が停止したようです。例外がスローされるのを見なくなったので、これを回答として受け入れます。
edit 4/04:もう少し詳しく説明します。 queryPurchasesメソッドのRemoteExceptionsとJSONExceptionsを処理するtry catchブロックがありますが、NullPointerException処理はありません。私がしようとしているのは、NullPointer例外処理を含めることです。そのため、querySkuDetailsを試行すると、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);
}
}
おそらく非同期操作を使用しています。 ... asyncメソッドを使用する場合、現在のIabHelperは安全ではありません。問題は、非同期操作の実行中はいつでも、メインスレッドで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
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 に感謝します。