【问题标题】:Google In-App Billing causing ExceptionGoogle 应用内结算导致异常
【发布时间】:2013-07-30 10:51:10
【问题描述】:

在我的一个 Android 应用程序中,我正在尝试从 Google 的应用内计费中简单地抓取库存,但它总是在

行出现错误
mHelper.queryInventoryAsync(mGotInventoryListener);

带有消息

IabHelper 未设置。无法执行操作:queryInventory

这是所有 IabHelper 代码。

    mHelper = new IabHelper(this, base64EncodedPublicKey);
    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
           public void onIabSetupFinished(IabResult result) {
              if (!result.isSuccess()) {
                 // Oh noes, there was a problem.
                 Log.d(TAG, "Problem setting up In-app Billing: " + result);
              }            
                 // Hooray, IAB is fully set up!  
           }
        });
    //check to see if ads have been removed(bought)
    IabHelper.QueryInventoryFinishedListener mGotInventoryListener 
       = new IabHelper.QueryInventoryFinishedListener() {
       public void onQueryInventoryFinished(IabResult result,
          Inventory inventory) {

          if (result.isFailure()) {
            // handle error here
          }
          else {
            // does the user have the premium upgrade?
            if(inventory.hasPurchase(REMOVE_ADS)) removeAdsPurchased = true;     
            // update UI accordingly
          }
       }
    };
    mHelper.queryInventoryAsync(mGotInventoryListener);

【问题讨论】:

标签: eclipse google-play in-app-billing


【解决方案1】:

只需使 checkNotDisposed() 方法同步,问题就会消失。这是因为它有时会在单独的线程中调用,并不总是具有最新的 mDisposed 值,可能已在主线程中设置:

private synchronized void checkNotDisposed()

【讨论】:

    【解决方案2】:

    卡尔的好东西。我“认为”我看到了类似的事情,尽管我的应用程序通过以下方式崩溃:

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

    在我的情况下,将设备旋转一个方向,然后立即返回原始方向有时会导致此崩溃。似乎存在“可能”发生这种崩溃的“时间窗口”(由于卡尔解释的 IAB 的异步性质)。

    我的解决方法

    我的“修复”是让 mHelper 成为静态的,并且只实例化它if (mHelper == null),而不是在活动的 onDestroy() 方法中销毁它。这样一来,一旦设置完成,它就会一直存在,无需再担心异步操作(由设备方向引起)。

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

    【讨论】:

    • 当然,如果 Android 杀死了您的进程,那么静态 mHelper 将被重置为 null,您将检测到并创建一个新的 IabHelper 对象来分配给它,而如果对Android 的一部分,或者如果它只杀死你的活动,那么 mHelper 将保持不变。在方向更改的情况下,Android 将仅重新启动正在运行的活动,这可能是您之前处理 mHelper 的代码导致您上面报告的错误的地方(因为 mHelper 引用了一个已处理的对象)。也可以自己处理方向变化。
    【解决方案3】:

    简短的回答是您的 queryInventoryAsync() 调用应该从您的 onIabSetupFinished() 方法内部进行。这是一个异步调用,因此在调用该回调告诉您助手与计费服务的通信已建立之前,您不能只继续使用 IabHelper 实例。当前编写代码的方式,您有一个竞争条件,并且您的 queryInventoryAsync() 调用将赢得该竞争并在 IabHelper 对象设置之前尝试使用它,这就是您的问题的原因。

    此外,依赖此对象的 UI 处理程序中的任何其他代码(例如,启动购买的按钮的处理程序)都应测试完全设置的 IabHelper 对象,并且不应允许用户使用该 UI元素,直到在 onCreate() 中创建的 IabHelper 实例成功完成设置。处理这种情况的最简单方法是简单地禁用此类 UI 元素,直到调用设置回调以指示设置已成功完成。

    这是最简单的部分。更严重的问题发生在 onCreate() 方法运行后立即发生的操作(即不受用户控制),这需要使用完全设置的 IabHelper 实例。这通常是活动生命周期调用的结果 - 特别是 onResume() (如果有需要 IabHelper 实例的事情,必须在您的应用程序每次进入前台时完成,而不是在 onCreate 时只是 () 被调用),最值得注意的是,在 onActivityResult() 中(当用户完成或中止与计费界面的交互时调用 - 例如,作为进行应用内支付的一部分)。

    问题是您的应用程序可能会被操作系统停止(例如,当用户开始购买时为计费界面本身腾出空间),导致您的 IabHelper 实例与您的应用程序一起被销毁,并且该实例将下次调用 onCreate() 时必须重新生成,并且设置将再次在 onCreate() 中启动,并且您需要再次等待设置完成,然后再对该对象执行任何其他操作。

    可能发生这种情况的一个值得注意的情况是在购买过程中用户与计费界面的交互过程中。该交互的结果将通过 onActivityResult() 传递给您的应用程序,它本身需要使用完全设置的 IabHelper 对象,因此如果您的应用程序在用户与计费服务交互时从内存中刷新(或取消)购买,然后 onActivityResult() 将不得不等待 IabHelper 实例再次设置(在它在 onCreate() 中重新创建之后才能使用它。

    处理此问题的一种方法是设置并发布到需要 IabHelper 实例的待处理操作队列,您的 onResume() 和/或 onActivityResult() 代码将添加到该队列,并由您的 onIabSetupFinished( ) 方法,一旦 IabHelper 设置(由 onCreate() 启动)完成。

    这不是微不足道的。上次我检查时,TrivialDrive 示例应用程序没有处理上述情况。

    测试这种用例的最佳方法是使用开发人员选项“不要保留活动”,这会导致您的应用在用户每次离开时被销毁,以模拟操作系统在它发生时会做什么需要回收内存,以便您可以确保您的应用在这些条件下工作。

    【讨论】:

    • 这是一个惊人的反应。我才 4 个月进入 Android 开发,所以我不是很了解所有内容,但我会努力让我的应用程序启动并运行。
    • 如果您使用随 SDK 分发的示例代码,即使您做对了,也会出现此错误。此特定错误已在官方市场计费 git 存储库中修复:code.google.com/p/marketbilling/source/checkout
    • 是的,我也收到了 TrivialDrive 演示已修复的通知,但没有尝试过,因为我已经在自己的应用程序中修复了问题。
    猜你喜欢
    • 2016-02-22
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    • 2019-01-16
    • 2015-10-31
    • 2013-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多