5

AndroidのImplementing In-app Billingガイドに従ってアプリ内課金(v3)を実装しました。アプリ請求 - 急速なデバイスオリエンテーション - クラッシュ(IllegalStateException)

すべては問題ありません。デバイスを回転させてすぐに元の向きに戻してください。実際には、時にはそれが動作し、時にはそれがでクラッシュ:

java.lang.IllegalStateException: IabHelper was disposed of, so it cannot be used.

私は肯定的ではないんだけれども、これは、IABの非同期性に関係しているようです。

どのような考えですか?

答えて

6

どこかの活動のライフサイクルでは、あなたはその同じを使用しようとした、mHelper.dispose()と呼ばれるので、あなたはおそらく、例外を取得しています後でインスタンスを配置します。私の推奨は、onDestroy()にmHelperを処分し、それをonCreate()に再作成することです。

ただし、IabHelperとデバイスのローテーションに関する別の問題が発生します。この問題は次のようになります。アクティビティのonCreate()では、IHBHelperインスタンスmHelperを作成して設定します。その後、mHelper.launchPurchaseFlow(...)に電話をかけると、IABポップアップダイアログがアクティビティの上に浮かんで表示されます。その後、デバイスを回転すると、IubHelperインスタンスはonDestroy(...)に処分され、onCreate(...)に再作成されます。 IABダイアログは引き続き表示され、購入ボタンを押すと購入が完了します。アクティビティでonActivityResult()が呼び出され、当然mHelper.handleActivityResult(...)が呼び出されます。問題は、launchPurchaseFlow(...)がIabHelperの再作成されたインスタンスで呼び出されたことがないことです。現在のインスタンスでlaunchPurchaseFlow(...)が以前に呼び出された場合、IabHelperはhandleActivityResult(...)のアクティビティー結果のみを処理します。 OnIabPurchaseFinishedListenerは決して呼び出されません。

私の解決策は、launchPurchaseFlow(...)を呼び出さずにhandleActivityResult(...)と期待するようにIabHelperを修正することでした。私は、これはhandleActivityResult(...)が呼び出されたときIabHelperがリスナーにonIabPurchaseFinished(...)を呼び出すようになります

public void expectPurchaseFinished(int requestCode, OnIabPurchaseFinishedListener listener) 
{ 
    mRequestCode = requestCode; 
    mPurchaseListener = listener; 
} 

IabHelper.java

に次を追加しました。 IabHelperの私の全体のコピーがここに https://gist.github.com/benhirashima/7917645を見つけることができます

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{ 
    mHelper.expectPurchaseFinished(requestCode, mPurchaseFinishedListener); 
    mHelper.handleActivityResult(requestCode, resultCode, data); 
} 

:次に、あなたがこれを行います。私がIABHelperのコピーをthis commitにあるバージョンで更新しました。これはいくつかのバグを修正し、Android SDK Managerには公開されていません。また、newer commitsがありますが、それにはnew bugsが含まれているため、使用しないでください。

+0

回転イベントを処理するためのきれいな解決策。 expectPurchaseFinishedが意味することを理解するのに苦労しましたが、結果を処理する直前にpurchaseFinishedListenerの新しいインスタンスを設定していることに気付きました。アクティビティとiabHelperがあったとしても、購買済みイベントを処理するリスナーが存在することが保証されます。再作成。 –

+0

同じ考え方でmPurchasingItemTypeを処理することができます(たとえば、onSaveInstanceStateとonRestoreInstanceStateを使用し、正しい項目タイプが設定されていない場合は、subsとinappの両方を使用している場合のみ問題です)。 –

0

私はmHelperを静的にしようとしましたが、(mHelper == null)場合にのみインスタンス化し、アクティビティのonDestroy()メソッドでインスタンスを破棄しませんでした。また、アプリケーションコンテキストをIabHelperに渡します。このように、一度設定すると、それは固執し、非同期操作(デバイス方向による原因)をもう心配する必要はありません。

は、ここに私のコードの概要です:これは右の修正やではありませんが、それは他の人を助ける場合には、私はそれを言及しようと思いました場合

static IabHelper mHelper; 
public void onCreate(Bundle savedInstanceState) { 
    ... 
    if (mHelper == null) { 
     mHelper = new IabHelper(getApplicationContext(), base64EncodedPublicKey); 
     mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { 
      ... 
     }); 
    } 
    ... 
} 

protected void onDestroy() { 
    ... 
    // Don't do ANYTHING to mHelper, so it will stick around on orientation change 
} 

わかりません。ここで

+0

私は同じことをすることを考えていましたが、これに望ましくない副作用があるかどうかわかりません。 IabHelperを維持するということは、InAppBillingServiceへの恒久的なサービス接続を維持することを意味します。これに何か問題がありましたか? –

+0

これは古い問題ですが...アプリケーションコンテキストを渡すのは問題ありません。ソースを見ると、アクティビティやアプリケーションコンテキストを使用することができます。https://code.google.com/p/marketbilling /source/browse/v3/src/com/example/android/trivialdrivesample/util/IabHelper.java?r=5f6b7abfd0534acd5bfc7c14436f4500c99e0358 – Darussian

+0

私のためにmHelperを静的にする。 – deko

2

は、私がやったことだ:IabHelperをインスタンス化し、startSetup()を呼び出すため

コードがonCreate()内にあるため、デバイスを回転させたとき、それはあまりにも長い間、あなたが自分で設定変更を処理していないとして、再作成されます。

また、onActivityResult()の冒頭に.handleActivityResult()と呼んでいることをご確認ください。これにより、購入ダイアログが閉じられた後でIabHelper参照が正しくクリーンアップされます。

これらの2つの機能を使用すると、クラッシュは発生しません。あなたはlaunchPurchaseFlow()への呼び出しで購入ダイアログを起動して、デバイスを回転させる場合は、ダイアログが開いたままになります

が、今、あなたのActivityさんIabHelper参照はonCreate()が呼び出されているため、上書きされています。しかし、あなたはもう一つのことに気づくでしょうデバイス回転時。このため、ダイアログを閉じると、新しいIabHelperhandleActivityResult()メソッドが呼び出されますが、先にlaunchPurchaseFlow()に渡されたrequestCodeと一致しないため、onPurchaseFinishedListenerは通知されません。このケース(ダイアログが開いているときの端末の回転)を処理するには、onActivityResult()の内部のrequestCodeを処理する必要があります。ダイアログが閉じられたので、onPurchaseFinishedListenerの中で何をしたかを模倣したいと思うでしょう。私はちょうどそれを見つけるためにqueryInventoryAsync()に電話しました。

私はそれが理想的な解決策であるかどうかはわかりませんが、それは私にとってはうまくいきます。私はあなたのようにIabHelper参照にぶら下げてみましたが、セットアップ状態を失うという奇妙な問題を見ましたが、再設定することはできません。

私がやった最後のことは、アンドロイドソースの最新のものを使用して請求用ユーティリティクラスを更新することでした。 SDKマネージャにプッシュされていないいくつかのバグ修正があります。それらのほとんどは、疑問のnullチェックですが、クラッシュを防ぐために、いくつかの改善があります。

latest changeset

0

私は彼らがこの問題を解決していなかったSOの多くの提案を試みた後、私は問題を解決し、このシンプルなnullチェックしてみました:

まず私はmHelperがnullの場合、新しいインスタンスを作成して確認:

のonCreate

if (mHelper == null) { 
    mHelper = new IabHelper(this, base64EncodedPublicKey); 
} 

そして私は再びmHelperにnullをチェック内の他の実装を追加しました:

//noinspection ConstantConditions 
if (mHelper != null){ 

    mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() { 
     public void onQueryInventoryFinished(IabResult result, Inventory inventory) { 
     } 
    }; 
    mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { 
     public void onIabPurchaseFinished(IabResult result, Purchase purchase) { 
     } 
    }; 
    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { 
     public void onIabSetupFinished(IabResult result) { 
     } 
    }); 
} 
そしてもちろん、あなたはヘルパー処分しなければならない:問題はまだ抵抗する

@Override 
public void onDestroy() { 
    super.onDestroy(); 
    if (mHelper != null) 
     mHelper.dispose(); 
    mHelper = null; 
} 

場合は、あなたのIabHelperクラスを更新します。

関連する問題