在我的一个Android应用程序中,我试图从Google应用内结算中实现广告资源的简单获取,但是却不断给我错误
mHelper.queryInventoryAsync(mGotInventoryListener);
消息是
这是所有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);
最佳答案
简短的答案是,应该从onIabSetupFinished()方法内部进行queryInventoryAsync()调用。这是一个异步调用,因此您不能仅继续使用IabHelper实例,直到调用该回调以告知您已建立帮助程序与计费服务的通信为止。当前编写代码的方式,您遇到了争用情况,并且您的queryInventoryAsync()调用将赢得这场争夺,并尝试在设置IabHelper对象之前使用它,这是造成问题的原因。
另外,依赖于此对象的UI处理程序中的任何其他代码(例如,发起购买的按钮的处理程序)都应测试是否已完全设置IabHelper对象,并且除非允许用户使用该UI元素,否则,在onCreate()中创建的IabHelper实例已成功完成设置。处理这种情况的最简单方法是简单地禁用此类UI元素,直到调用设置回调以指示安装成功完成为止。
那是容易的部分。当您的操作在onCreate()方法运行后立即发生(即,不受用户控制)时,会发生更严重的问题,这些操作需要使用完全设置的IabHelper实例。这通常是由于 Activity 生命周期调用而发生的-具体来说就是onResume()(如果有一些需要IabHelper实例的事情,那么您的应用每次出现在前台时(而不仅仅是在调用onCreate()时)都必须完成),并且最值得注意的是,在onActivityResult()中(当用户完成或中止与计费界面的交互时调用,例如,作为应用内付款的一部分)。
问题在于,您的应用可能会被操作系统停止(例如,在用户发起购买时为结算界面本身腾出空间),从而导致IabHelper实例与您的应用一起被销毁,并且该实例必须下次调用onCreate()时,将重新生成该对象,然后将再次在onCreate()中启动安装程序,并且您需要再次等待安装完成才能对该对象执行任何其他操作。
可能发生这种情况的一种值得注意的情况是,在用户与计费界面的交互过程中,这是购买过程的一部分。交互的结果将通过onActivityResult()传达给您的应用,该对象本身需要使用完全设置的IabHelper对象,因此,如果在用户与计费服务进行交互以使( (或取消)购买,则onActivityResult()将必须等待IabHelper实例重新设置(在onCreate()中重新创建它之后,才能使用它)。
处理此问题的一种方法是,将需要IabHelper实例的onResume()和/或onActivityResult()代码添加到该待处理操作的队列中,并将其发布到该队列中,并通过onIabSetupFinished()方法对该队列进行一次处理IabHelper设置(由onCreate()初始化)已完成。
这不是小事。上次我检查时,TrivialDrive示例应用程序无法处理上述情况。
测试这种用例的最佳方法是使用开发人员选项“不保留 Activity ”,该选项使您的应用在每次用户离开时都会被销毁,以模拟操作系统在需要回收时将执行的操作内存,以便您可以确保您的应用在这种情况下可以正常工作。