Android应用内购上线后触发IllegalStateException崩溃问题求助
你遇到的这个java.lang.IllegalStateException是IabHelper生命周期管理不当导致的典型问题,测试环境正常但生产环境出问题,主要是因为线上用户的操作场景更复杂(比如后台进程被系统回收、快速切换页面等),而你的代码里缺少对IabHelper状态的必要校验和资源释放逻辑。
问题根源分析
从崩溃栈来看,异常来自IabHelper的checkNotDisposed、checkSetupDone等方法,说明你在以下场景调用了IabHelper的方法:
- IabHelper已经被
dispose()销毁后 - IabHelper的初始化(
startSetup)还未完成时 - 异步回调执行时,对应的Activity已经被销毁,IabHelper实例处于无效状态
具体修复方案
1. 正确管理IabHelper的生命周期,在Activity销毁时释放资源
你的代码里只在onCreate初始化了IabHelper,但没有在Activity销毁时清理资源,这会导致异步回调执行时IabHelper已经处于非法状态。在你的Activity中添加以下代码:
@Override protected void onDestroy() { super.onDestroy(); // 释放IabHelper资源,避免内存泄漏和非法状态调用 if (mHelper != null) { mHelper.dispose(); mHelper = null; } }
2. 在调用IabHelper方法前,先校验状态
在调用queryInventoryAsync、launchPurchaseFlow等方法前,必须确保IabHelper已经初始化完成且未被销毁。修改你的checkItem方法:
public void checkItem() { // 先检查mHelper是否存在、已完成初始化且未被销毁 if (mHelper != null && mHelper.isSetupDone() && !mHelper.isDisposed()) { mHelper.queryInventoryAsync(mReceivedInventoryListener); } }
3. 增强异步回调中的安全校验
在异步回调(比如onQueryInventoryFinished、onIabPurchaseFinished)中,除了检查mHelper == null,还要校验是否已被销毁,避免后续操作触发异常:
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() { public void onQueryInventoryFinished(IabResult result, Inventory inventory) { // 双重校验:实例存在且未被销毁 if (mHelper == null || mHelper.isDisposed()) { return; } Purchase purchase = inventory.getPurchase(ITEM_SKU); if (purchase != null) { removeAds(); } } }; IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { if (mHelper == null || mHelper.isDisposed()) { return; } if (result.isFailure()) { checkItem(); return; } else if (purchase.getSku().equals(ITEM_SKU)) { removeAds(); } } };
4. 跟踪初始化状态,避免提前调用方法
可以添加一个布尔变量标记IabHelper是否初始化完成,防止在startSetup回调前就调用内购相关方法:
private boolean mIsIabSetupComplete = false; // 在onCreate的startSetup回调中更新状态 mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { public void onIabSetupFinished(IabResult result) { if (!result.isSuccess()) { Log.d(TAG, "In-app Billing setup failed: " + result); mIsIabSetupComplete = false; } else { Log.d(TAG, "In-app Billing is set up OK"); mIsIabSetupComplete = true; // 初始化完成后再执行首次库存查询等操作 checkItem(); } } }); // 然后在checkItem中增加这个状态校验 public void checkItem() { if (mHelper != null && mIsIabSetupComplete && !mHelper.isDisposed()) { mHelper.queryInventoryAsync(mReceivedInventoryListener); } }
为什么测试环境没问题?
测试时你通常不会频繁触发Activity销毁重建、系统回收进程等场景,IabHelper的状态一直处于有效状态,所以不会触发异常。但线上用户的操作场景多样,这些边缘情况很容易出现,因此必须做好状态校验和资源管理。
内容的提问来源于stack exchange,提问作者user2872856

