I got an error and I'm going mad because happen only in some circumstances but I really don't understand when, maybe a more expert eye can help me:
From the Google tutorials I took the code for make an in-app purchase, briefly this code do:
Initialize the In-App Service
Retrieve the price
of the objectStart the in-purchase
if the user click the button "Buy".Now, in all the tests that I did this work fine (more devices and API) BUT I got ton of reports that say: thrown a NullPointerException
on mHelper
.
I think that this happen in on the OnDestroy() when the service is disposed but i'm not sure and I couldn't fix it(Complete Error Log in the end).
Here is my cleaned and commented as much as 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 the error:
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 is some involved method of the Google IabHelper class (Probably you'll NOT need to read this) They are just 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 the Constructor of IabHelper:
public IabHelper(Context ctx, String base64PublicKey) {
mContext = ctx.getApplicationContext();
mSignatureBase64 = base64PublicKey;
logDebug("IAB helper created.");
}
Here is the complete IabHelper class.
Recap:
Tell me if you can see where/when the NullPointerException
of the variable mHelper
is thrown. I couldn't from the code and test with virtual and physical devices since work fine.
I'm pretty much sure that the error is thrown after that the Activity is closed but I don't understand why for fix it.
Write if you need more info. Thank to all!
You should try to avoid using getApplicationContext() as much as possible, as this will highly increase the chance of getting Force Closes.
Use Activity context. If you are create object of IabHelper in Activity then Pass ActivityName.this(means Activity context).
If you are in Fragment the use getActivity().
And in IabHelper class use like this::
public IabHelper(Context ctx, String base64PublicKey) {
mContext = ctx;
mSignatureBase64 = base64PublicKey;
logDebug("IAB helper created.");
}
I hope it works fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With