1

我正在尝试为 Xamarin 的 Amazon IAP 插件实现包装器。它以下列方式使用基于事件的系统:

您可以发起方法调用并监听事件。方法调用发起请求,其中一些返回响应。事件是系统生成的异步消息,它们响应方法调用而发送,以将请求的数据返回给您。 在这里查看更多

我的目标是将这个基于事件的系统包装到一些 API 中,这样我就可以将插件与任务一起使用,这样我就可以使用async-await语法。为了实现这一点,我TaskCompletionSource在下面的例子中使用了类似的东西:

public async Task<bool> GetProductInfoAsync(params string[] productIds)
{
    var iapService = AmazonIapV2Impl.Instance;
    var tcs = new TaskCompletionSource<bool>();
    var skus = new SkusInput { Skus = productIds.ToList() };
    var requestId = iapService.GetProductData(skus).RequestId;

    GetProductDataResponseDelegator delegator = null;
    delegator = new GetProductDataResponseDelegator(response => 
    {
        if(response.Id == requestId) {
            var result = GetResultFromResponse(response);
            tcs.SetResult(result);
            //iapService.RemoveGetProductDataResponseListener(delegator.responseDelegate);
        }
    });

    iapService.AddGetProductDataResponseListener(delegator.responseDelegate);
    return await tcs.Task;
}

如果该方法被调用一次,此代码似乎可以正常工作,但如果它被连续调用两次,则应用程序立即崩溃,并且打印到控制台的唯一内容是以下消息..

[mono] Unhandled Exception:
[mono] System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Collection was modified; enumeration operation may not execute.

..这根本没有意义。

那么我在这里有什么明显的遗漏吗?或者它可能是插件的错误?

我已经使用上面的代码创建了一个存储库,因此您可以重现该问题。这是我的游乐场,所以请忽略项目的整个结构,只关注AmazonIAPServiceMainActivity类。

提示 1: 注释行//iapService.RemoveGetProductDataResponseListener(delegator.responseDelegate);也会导致崩溃,消息相同,但在第一次调用该方法时已经发生。

提示 2: 包含AmazonIAPService一个注释方法,它await Task.Delay(TimeSpan.FromMilliseconds(1))以一种我真的不喜欢的非常 hacky 的方式使用和解决上面的问题。

4

1 回答 1

0

问题似乎是这些函数必须异步运行。在文档中也提到了here 。因此,一旦您以某种方式同步运行这些函数,它们就会抛出异常,我不知道库中发生了什么,但您的 hacky 解决方案是实际的解决方案。如果您编写如下函数。它也有效。

  PurchaseResponseDelegator delegator = null;
                delegator = new PurchaseResponseDelegator(async response =>
                {
                    await Task.Run(() =>
                    {
                        if (response.RequestId == requestId)
                        {
                            var result = GetPurchaseEventHandler(response);
                            var sucess = taskCompletionSource.TrySetResult(result);        
                            context.RemovePurchaseResponseListener(delegator.responseDelegate);
                        }
                    } );
                });
                // Register for an event
                context.AddPurchaseResponseListener(delegator.responseDelegate);

尽管有 async-await 解决方案,但我遇到的另一个异常,不知何故,它总是taskCompletionSource.SetResult(result);只为 PurchaseUpdates 函数的行抛出异常。如果我改用这条线 var sucess = taskCompletionSource.TrySetResult(result);,它可以正常工作

于 2018-07-28T00:36:23.683 回答