web-dev-qa-db-fra.com

API de facturation v3 IabHelper NullPointerException

edit 4/15: Catching nullpointer dans IabHelper semble avoir arrêté ce problème. Je ne vois plus les exceptions levées, je vais accepter cela comme une réponse.


edit 4/04: Un petit peu plus en profondeur. Il existe des blocs catch qui gèrent RemoteExceptions et JSONExceptions pour la méthode queryPurchases, mais aucune gestion NullPointerException. Ce que je vais essayer de faire, c'est d'inclure la gestion des exceptions NullPointer afin que IabHelper ressemble à ceci lorsque vous essayez de querySkuDetails:

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

Je viens de déposer un bug sur ceci:

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


edit 3/25: eh bien, je reçois toujours ce crash ... maintenant cela se produit lorsque vous essayez d'obtenir un contexte à la ligne 3 de l'extrait suivant de IabHelper:

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

C'est frustrant, car dans mon manifeste, j'utilise toujours le nom de chemin complet de mon application pour "nom".

Exemple "com.myappname.blah.ClassName"

J'ai également essayé de transmettre ceci, MyClass.this, getApplicationContext () à mHelper. Cependant, ils produisent tous les mêmes résultats NullPointer de manière aléatoire à partir de périphériques dans la nature. J'ai aussi essayé name = ". MyClass" dans le manifeste. Voici à quoi cela ressemble actuellement:

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

edit 18/03/13: Je reçois toujours des exceptions, même avec la nouvelle version de IabHelper déployée le 3/17. 

Je commence à voir un modèle ici, que les plantages se produisent tous lorsque l'on essaie d'obtenir un contexte lors de l'exécution de mContext.getPackageName (). Je suis curieux de savoir pourquoi cela fonctionne sur tous mes périphériques de test, et je ne peux pas reproduire ce crash, et il semble ne concerner qu'un petit nombre de périphériques.

Voici le nouveau crash:

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)

Causée par IabHelper ...

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

edit 17/03/13: Je vois qu'il y a eu beaucoup de corrections de bugs publiées au cours des derniers mois, je vais essayer le dernier code disponible ici et voir si cela résout le problème:

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


Dans l'une de mes applications, j'utilise l'API de facturation et le code standard inclus dans celle-ci.

J'utilise la dernière version de l'API de facturation disponible via le gestionnaire de SDK à compter du 16/03/2013.

Dans mon activité, j'interroge l'inventaire à l'aide des éléments suivants:

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

Je reçois plusieurs rapports NullPointerException à l'état sauvage à partir de la classe IabHelper pour les périphériques suivants. Je ne peux pas reproduire le problème ni trouver d’informations concernant ces accidents. C’est la raison pour laquelle je publie cette question.

J'ai d'innombrables autres contrôles pour les valeurs NULL et les blocs try/catch dans la partie "développeur" de l'API de facturation, y compris dans onQueryInventoryFinished. Je sais donc que cette exception n'est pas renvoyée de "mon code" (car je ne capture pas les plantages de l'une des classes de mon application), mais est au contraire jeté de l'intérieur de l'IabHelper lui-même. Je n'ai pas modifié IabHelper autre que ce correctif recommandé: https://stackoverflow.com/a/14737699

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)

Causée par 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)

Causée par IabHelper ...

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

edit 4/15: Catching nullpointer dans IabHelper semble avoir arrêté ce problème. Je ne vois plus les exceptions levées, je vais accepter cela comme une réponse.


edit 4/04: Un petit peu plus en profondeur. Il existe des blocs catch qui gèrent RemoteExceptions et JSONExceptions pour la méthode queryPurchases, mais aucune gestion NullPointerException. Ce que je vais essayer, c’est d’inclure la gestion des exceptions NullPointer afin que IabHelper se présente comme ceci lors de l’essai de querySkuDetails:

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

Je viens de déposer un bug sur ceci:

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


Changement

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

Changement

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

Vous utilisez probablement des opérations asynchrones. Le IabHelper actuel n'est pas sûr si vous utilisez les ... méthodes asynchrones. Le problème est que, à tout moment, une opération asynchrone en cours d'exécution peut être appelée sur le thread principal. Dans ce cas, vous obtiendrez NullPointerExceptions et IllegalStateExceptions. 

Voici le correctif pour le réparer:

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

Ou téléchargez le correctif ici . http://code.google.com/p/marketbilling/issues/detail?id=139&thanks=139&ts=1375614409

20
tmanthey

Modifiez légèrement le début de la méthode queryPurchases pour ressembler à ceci:

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

Merci à sebastie d’avoir signalé la cause.

0
Thunder

tmantheypatch nécessite également

mDisposeRequested = false;

après la disposition a lieu

0
Markos Evlogimenos