我根据Android的实现应用内计费指南,实现了应用内计费(v3)。
一切都很好,直到我旋转设备,然后立即将其旋转回原始方向。实际上,有时它可以正常工作,有时会崩溃并显示以下错误:
java.lang.IllegalStateException: IabHelper已被处理,因此无法使用。
似乎这与IAB的异步性质有关,但我不确定。
有什么想法吗?
我根据Android的实现应用内计费指南,实现了应用内计费(v3)。
一切都很好,直到我旋转设备,然后立即将其旋转回原始方向。实际上,有时它可以正常工作,有时会崩溃并显示以下错误:
java.lang.IllegalStateException: IabHelper已被处理,因此无法使用。
似乎这与IAB的异步性质有关,但我不确定。
有什么想法吗?
mHelper.dispose()
,然后尝试在稍后使用同一已处理的实例而导致此异常。我的建议是只在onDestroy()
中处理mHelper并在onCreate()
中重新创建它。onCreate()
中,您创建IabHelper实例mHelper并设置它。稍后,您调用mHelper.launchPurchaseFlow(...)
,IAB弹出对话框出现在您的activity上方。然后您旋转设备,IabHelper实例在onDestroy(...)
中被处理,然后在onCreate(...)
中重新创建。IAB对话框仍然显示,您按下购买按钮,购买完成。然后在您的activity上调用onActivityResult()
,您自然会调用mHelper.handleActivityResult(...)
。问题是,在重新创建的IabHelper实例上从未调用过launchPurchaseFlow(...)
,因此IabHelper仅在handleActivityResult(...)
中处理活动结果,如果之前已在当前实例上调用了launchPurchaseFlow(...)
。您的OnIabPurchaseFinishedListener永远不会被调用。launchPurchaseFlow(...)
的情况下期望handleActivityResult(...)
。我在IabHelper.java中添加了以下内容。public void expectPurchaseFinished(int requestCode, OnIabPurchaseFinishedListener listener)
{
mRequestCode = requestCode;
mPurchaseListener = listener;
}
handleActivityResult(...)
时,在监听器上调用onIabPurchaseFinished(...)
。然后,您需要执行以下操作:@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
mHelper.expectPurchaseFinished(requestCode, mPurchaseFinishedListener);
mHelper.handleActivityResult(requestCode, resultCode, data);
}
我的整个IabHelper副本可以在此处找到https://gist.github.com/benhirashima/7917645。请注意,我使用此提交版本更新了我的IabHelper副本,该版本修复了一些错误,尚未发布在Android SDK Manager中。还要注意,有更新的提交版本,但它们包含新错误,不应使用。
launchPurchaseFlow()
来启动购买对话框,然后旋转设备,对话框将保持打开状态,但此时您的Activity
的IabHelper
引用已被覆盖,因为设备旋转时会调用onCreate()
。因此,当您关闭对话框时,新的IabHelper
的handleActivityResult()
方法会被调用,但它与您之前传递给launchPurchaseFlow()
的requestCode
不匹配,因此您的onPurchaseFinishedListener
将无法收到通知。为了处理这种情况(即在对话框打开时旋转设备),您需要在onActivityResult()
中自己处理requestCode
。由于对话框已关闭,您需要模拟您在onPurchaseFinishedListener
中所做的操作(查找用户是否实际购买了某些内容)。我只是调用了queryInventoryAsync()
来查找这一点。IabHelper
的引用,但我遇到了一些奇怪的问题,它会失去设置状态,但又不允许我重新设置它。在 Stack Overflow 上尝试了很多建议都没有解决这个问题之后,我尝试了这个简单的 null
检查,它解决了这个问题:
首先我检查了 mHelper
是否为 null,然后创建一个新实例:
在 onCreate 中
if (mHelper == null) {
mHelper = new IabHelper(this, base64EncodedPublicKey);
}
我在 mHelper
的 null 检查内再次添加了其他实现:
//noinspection ConstantConditions
if (mHelper != null){
mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
}
};
mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
}
};
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
}
});
}
当然,你应该处理辅助程序:
@Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null)
mHelper.dispose();
mHelper = null;
}
static IabHelper mHelper;
public void onCreate(Bundle savedInstanceState) {
...
if (mHelper == null) {
mHelper = new IabHelper(getApplicationContext(), base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
...
});
}
...
}
protected void onDestroy() {
...
// Don't do ANYTHING to mHelper, so it will stick around on orientation change
}
不确定这是否是正确的解决方法,但我想提及它以帮助其他人。
expectPurchaseFinished
的含义,但最终我意识到,在处理结果之前,您正在设置一个新的purchaseFinishedListener
实例,这确保了即使重新创建了活动和iabHelper,也有一个监听器来处理已购买完成的事件。 - Kevin Lee