【问题标题】:Android In-app purchase NullPointerExceptionAndroid 应用内购买 NullPointerException
【发布时间】:2023-03-23 13:14:01
【问题描述】:

我遇到了一个错误,我要疯了,因为只在某些情况下发生,但我真的不明白什么时候,也许更专业的眼睛可以帮助我:

我从谷歌教程中获取了用于进行应用内购买的代码,简要说明此代码

  1. Initialize the In-App Service
  2. 对象的Retrieve the price
  3. Start the in-purchase 如果用户点击“购买”按钮。

现在,在我完成这项工作的所有测试中(更多设备和 API)但是我收到大量报告说:在 mHelper 上抛出了 NullPointerException

我认为这发生在 OnDestroy() 服务被处置但我不确定并且我无法修复它(最后完成错误日志)。

这是我清理并尽可能多地注释的代码:

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

这是错误:

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)

以下是 Google IabHelper 类的一些相关方法(可能您不需要阅读此内容)它们只是在错误日志中提到并由 Google 编写:

处置:

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

启动设置:

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

以及 IabHelper 的构造函数:

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

Here 是完整的 IabHelper 类。

回顾:

告诉我您是否可以看到变量mHelperNullPointerException 被抛出的位置/时间。由于工作正常,我无法从代码中使用虚拟和物理设备进行测试。

我很确定在 Activity 关闭后会引发错误,但我不明白为什么要修复它。

如果您需要更多信息,请写信。谢谢大家!

【问题讨论】:

  • 你能用完整的堆栈跟踪更新你的问题吗
  • 当然,问题已更新
  • 你能调试看看mContext返回为null吗?
  • 当我调试工作正常且 mContext != Null 时,我无法重现该错误,但可以肯定它发生在 Activity 关闭后
  • @GMX,mHelper 的使用在代码中的哪个位置引发了 NPE?

标签: java android nullpointerexception in-app-purchase


【解决方案1】:

您将 new IabHelper.OnIabSetupFinishedListener() {...} 传递给 startSetup() 但 mHelper.startSetup() 不保留引用,并且 onCreate() 也不保留引用。看起来您有一个属性 (mPurchaseListener) 来保存一个侦听器,但没有使用它 - 相反,您正在创建一个匿名类并将其传递给 startSetup()...然后您的实例正在被垃圾收集,因为那里没有参考。

【讨论】:

    【解决方案2】:

    您应该尽量避免使用 getApplicationContext(),因为这会大大增加强制关闭的机会。

    使用活动上下文。如果您在 Activity 中创建 IabHelper 对象,则传递 ActivityName.this(表示 Activity 上下文)。

    如果你在 Fragment 中使用 getActivity()。

    在 IabHelper 类中这样使用::

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

    我希望它能正常工作。

    【讨论】:

    • 我会尽快测试这个
    猜你喜欢
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 2013-04-11
    相关资源
    最近更新 更多