Android In-app Purchase NullPointerException

I have a mistake, and I'm losing my mind because it happens only in certain circumstances, but I really don’t understand when, perhaps, a more experienced eye can help me:

In Google tutorials, I took the code to make an in-app purchase, in short this code :

  • Initialize the In-App Service
  • Retrieve the price object
  • Start the in-purchase if the user clicks the Buy button.

Now, in all the tests I did, this work is fine (more devices and APIs) BUT . I have a ton of reports that say: threw a NullPointerException on mHelper .

I think this happens in OnDestroy () when the service is configured, but I'm not sure, and I could not fix it (full error log at the end).

Here is my cleared and commented out maximum possible code:

 IabHelper mHelper; IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener; Activity c; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_show_room); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); c=this; //Initialize the In-App Service mHelper = new IabHelper(this, "my_key"); mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { public void onIabSetupFinished(IabResult result) { if (!result.isSuccess()) { //Problem setting up In-app Billing return; } if (mHelper == null) return; //Ask for the price List additionalSkuList = new ArrayList(); additionalSkuList.add("SKU_ID"); try { mHelper.queryInventoryAsync(true, additionalSkuList, mQueryFinishedListener); }catch (Exception e){ //Fail while asking the price } } }); //Buy Button Listener b_buy.setOnClickListener(new View.OnClickListener() { public void onClick(View V) { try { String payload= "my_payload" mHelper.launchPurchaseFlow(c, "SKU_ID",1111,mPurchaseFinishedListener, payload); } catch (Exception e) { //Error launching purchase flow. Another async operation in progress } } }); // Callback for when a purchase is finished mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { // if we were disposed of in the meantime, quit. if (mHelper == null) return; if (result.isFailure()) { //Error while buying return; } if (purchase.getSku().equals("SKU_ID")) { // bought the premium upgrade! } } }; } //For retrieve the price: IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() { public void onQueryInventoryFinished(IabResult result, Inventory inventory) { if (result.isFailure()) { return; } String z = inventory.getSkuDetails("SKU_ID").getPrice(); //The price of the object is + z !!! } }; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (mHelper == null) return; // Pass on the activity result to the helper for handling if (!mHelper.handleActivityResult(requestCode, resultCode, data)) { super.onActivityResult(requestCode, resultCode, data); } } @Override public void onDestroy() { super.onDestroy(); if (mHelper != null) mHelper.dispose(); mHelper = null; } @Override public void onBackPressed() { super.onBackPressed(); finish(); } } 

And this is a mistake:

 Exception java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference com.myproj.util.IabHelper.startSetup (IabHelper.java) __null__.dispose (IabHelper.java) __null__.launchPurchaseFlow (IabHelper.java) __null__.handleActivityResult (IabHelper.java) __null__.queryInventory (IabHelper.java) __null__.queryInventoryAsync (IabHelper.java) __null__.getResponseDesc (IabHelper.java) __null__.checkSetupDone (IabHelper.java) __null__.getResponseCodeFromBundle (IabHelper.java) __null__.getResponseCodeFromIntent (IabHelper.java) __null__.queryPurchases (IabHelper.java) __null__.querySkuDetails (IabHelper.java) com.myproj.util.IabHelper.startSetup (IabHelper.java) __null__.dispose (IabHelper.java) __null__.launchPurchaseFlow (IabHelper.java) __null__.handleActivityResult (IabHelper.java) __null__.queryInventory (IabHelper.java) __null__.queryInventoryAsync (IabHelper.java) __null__.getResponseDesc (IabHelper.java) __null__.checkSetupDone (IabHelper.java) __null__.getResponseCodeFromBundle (IabHelper.java) __null__.getResponseCodeFromIntent (IabHelper.java) __null__.queryPurchases (IabHelper.java) __null__.querySkuDetails (IabHelper.java) com.myproj.util.IabHelper.startSetup (IabHelper.java) __null__.dispose (IabHelper.java) __null__.launchPurchaseFlow (IabHelper.java) __null__.handleActivityResult (IabHelper.java) __null__.queryInventory (IabHelper.java) __null__.queryInventoryAsync (IabHelper.java) __null__.getResponseDesc (IabHelper.java) __null__.checkSetupDone (IabHelper.java) __null__.getResponseCodeFromBundle (IabHelper.java) __null__.getResponseCodeFromIntent (IabHelper.java) __null__.queryPurchases (IabHelper.java) __null__.querySkuDetails (IabHelper.java) com.myproj.util.IabHelper$2.run (IabHelper.java) java.lang.Thread.run (Thread.java:818) 

Here's some involved method of the Google IabHelper class (maybe you don't need to read this) . They are only mentioned in the error log and are written by Google:

Dispose:

 public void dispose() { logDebug("Disposing."); mSetupDone = false; if (mServiceConn != null) { logDebug("Unbinding from service."); if (mContext != null) mContext.unbindService(mServiceConn); } mDisposed = true; mContext = null; mServiceConn = null; mService = null; mPurchaseListener = null; } 

StartSetup:

  public void startSetup(final OnIabSetupFinishedListener listener) { // If already set up, can't do it again. checkNotDisposed(); if (mSetupDone) throw new IllegalStateException("IAB helper is already set up."); // Connection to IAB service logDebug("Starting in-app billing setup."); mServiceConn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { logDebug("Billing service disconnected."); mService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { if (mDisposed) return; logDebug("Billing service connected."); mService = IInAppBillingService.Stub.asInterface(service); String packageName = mContext.getPackageName(); try { logDebug("Checking for in-app billing 3 support."); // check for in-app billing v3 support int response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP); if (response != BILLING_RESPONSE_RESULT_OK) { if (listener != null) listener.onIabSetupFinished(new IabResult(response, "Error checking for billing v3 support.")); // if in-app purchases aren't supported, neither are subscriptions. mSubscriptionsSupported = false; return; } logDebug("In-app billing version 3 supported for " + packageName); // check for v3 subscriptions support response = mService.isBillingSupported(3, packageName, ITEM_TYPE_SUBS); if (response == BILLING_RESPONSE_RESULT_OK) { logDebug("Subscriptions AVAILABLE."); mSubscriptionsSupported = true; } else { logDebug("Subscriptions NOT AVAILABLE. Response: " + response); } mSetupDone = true; } catch (RemoteException e) { if (listener != null) { listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION, "RemoteException while setting up in-app billing.")); } e.printStackTrace(); return; } if (listener != null) { listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful.")); } } }; Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); serviceIntent.setPackage("com.android.vending"); if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) { // service available to handle that Intent mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE); } else { // no service available to handle that Intent if (listener != null) { listener.onIabSetupFinished( new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE, "Billing service unavailable on device.")); } } } 

and IabHelper constructor:

  public IabHelper(Context ctx, String base64PublicKey) { mContext = ctx.getApplicationContext(); mSignatureBase64 = base64PublicKey; logDebug("IAB helper created."); } 

Here is the full IabHelper class.

Summary:

Tell me if you can see where / when the NullPointerException mHelper variable is mHelper . I could not test the virtual and physical devices from the code, as it works fine.

I am pretty sure that after that the function will be closed, but I do not understand why fix it.

Write if you need more information. Thanks everyone!

+5
source share
2 answers

You should try to avoid using getApplicationContext () as much as possible, as this will greatly increase the chance of getting Force Closes.

Use action context. If you create an IabHelper object in an Activity, then Pass ActivityName.this (means the context of the action).

If you are in a Snippet, use getActivity ().

And in the IabHelper class use like this:

 public IabHelper(Context ctx, String base64PublicKey) { mContext = ctx; mSignatureBase64 = base64PublicKey; logDebug("IAB helper created."); } 

I hope everything will be OK.

+2
source

You pass new IabHelper.OnIabSetupFinishedListener() {...} to startSetup (), but mHelper.startSetup () does not save the link, and the onCreate () function does not save it. it looks like you have a property ( mPurchaseListener ) to hold the listener but not using it - instead, you create an anonymous class and pass it to startSetup () ... then your instance gets garbage collection because there are no references there.

0
source

Source: https://habr.com/ru/post/1263254/


All Articles