5

我根据 Android 的实现应用内计费指南实现了应用内计费 (v3)。

一切正常,直到我旋转设备,然后立即将其旋转回原来的方向。实际上,有时它可以工作,有时它会崩溃:

java.lang.IllegalStateException: IabHelper was disposed of, so it cannot be used.

似乎这与 IAB 的异步性质有关,尽管我并不积极。

有什么想法吗?

4

4 回答 4

6

您可能会遇到异常,因为在活动生命周期的某个地方,您调用了mHelper.dispose(),然后稍后尝试使用同一个已处置的实例。我的建议是只处理 mHelperonDestroy()并在onCreate().

但是,您将遇到 IabHelper 和设备旋转的另一个问题。问题是这样的:在您的活动中onCreate(),您创建 IabHelper 实例 mHelper 并进行设置。稍后,您调用mHelper.launchPurchaseFlow(...),IAB 弹出对话框出现在您的活动上方。然后旋转设备,IabHelper 实例被处理掉,onDestroy(...)然后重新创建onCreate(...)。IAB 对话框仍在显示,您按下购买按钮,购买完成。onActivityResult()然后在您的活动上调用,您自然会调用mHelper.handleActivityResult(...). 问题是,launchPurchaseFlow(...)从未在重新创建的 IabHelper 实例上调用过。IabHelper 仅在handleActivityResult(...)if中处理活动结果launchPurchaseFlow(...)之前已在当前实例上调用过。您的 OnIabPurchaseFinishedListener 永远不会被调用。

我对此的解决方案是修改 IabHelper 以允许您告诉它期望handleActivityResult(...)而不调用launchPurchaseFlow(...). 我将以下内容添加到 IabHelper.java

public void expectPurchaseFinished(int requestCode, OnIabPurchaseFinishedListener listener)
{
    mRequestCode = requestCode;
    mPurchaseListener = listener;
}

这将导致 IabHelper在被调用onIabPurchaseFinished(...)时调用侦听handleActivityResult(...)器。然后,你这样做:

@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 管理器中发布。另请注意,有较新的提交,但它们包含新错误,不应使用。

于 2013-12-11T22:19:20.800 回答
2

这是我所做的:

实例化IabHelperand 调用的代码startSetup()在 内onCreate(),因此只要您不自己处理配置更改,它将在设备旋转时重新创建。

另外,请确保您.handleActivityResult()onActivityResult(). 这将确保IabHelper在关闭购买对话框后正确清理您的参考。

有了这两件事,您应该不会再看到任何崩溃。但是你会注意到另外一件事:

如果您通过调用来启动购买对话框,launchPurchaseFlow()然后旋转设备,对话框将保持打开状态,但现在您ActivityIabHelper引用已被覆盖,因为onCreate()在设备旋转时调用。因此,当您关闭对话框时,会调用 newIabHelper的方法,但它与您之前传递给的handleActivityResult()方法不匹配,因此不会通知您。要处理这种情况(对话框打开时设备旋转),您需要自己处理. 由于对话框已关闭,您将想要模仿您在您的内部所做的事情(发现用户是否真的买了东西)。我只是打了个电话想知道这一点。requestCodelaunchPurchaseFlow()onPurchaseFinishedListenerrequestCodeonActivityResult()onPurchaseFinishedListenerqueryInventoryAsync()

我不确定这是否是理想的解决方案,但对我来说效果很好。我试着像你一样挂在IabHelper参考上,但我看到了奇怪的问题,它会失去设置状态,但不允许我重新设置它。

我做的最后一件事是使用来自 android 源的最新版本更新计费实用程序类。有一些错误修复尚未推送到 SDK 管理器。其中大多数是有问题的空检查,但有一些改进可以防止崩溃:

最新的变更集

于 2013-09-28T07:19:05.510 回答
0

我试图使 mHelper 静态,并且仅在 (mHelper == null) 时实例化它,而不是在活动的 onDestroy() 方法中销毁它。此外,将应用程序上下文传递给 IabHelper。这样,一旦设置完成,它就会一直存在,并且不再需要担心异步操作(由设备方向引起)。

这是我的代码的大纲:

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
}

不确定这是否是正确的解决方法,但我想我会提到它以防它帮助其他人。

于 2013-08-14T04:18:25.087 回答
0

在我在 SO 中尝试了许多他们没有解决这个问题的建议之后,我尝试了这个简单null的检查来解决这个问题:

首先我检查是否mHelper为空,然后创建一个新实例:

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

如果问题仍然存在,请更新您的IabHelper类。

于 2017-09-05T13:54:56.597 回答