等待时,Akavache的GetObject <T>挂起.知道这里有什么问题吗?

lar*_*eck 4 c# android portable-class-library xamarin.forms akavache

我有一个Xamarin.Forms应用程序,在我的App类中使用此代码(是的,这只是一个演示问题的示例):

    public App()
    {
        BlobCache.ApplicationName = "MyApp";
        BlobCache.EnsureInitialized();


        // The root page of your application
        MainPage = GetMainPage();
    }

    public object BlockingGetExternalUser()
    {
        return GetExternalUser().Result;
    }

    private async Task<object> GetExternalUser()
    {
        try
        {
            return await BlobCache.LocalMachine.GetObject<object>("user");
        }
        catch (KeyNotFoundException)
        {
            return null;
        }
    }
Run Code Online (Sandbox Code Playgroud)

密钥"用户"不存在,所以我希望得到一个KeyNotFoundException.但是我从来没有看到过抛出这个异常.相反,它只是"挂起",永远不会从await GetObject调用返回.

我在Android 5.0手机上运行此功能.

任何想法如何解决这一问题?我做了一些根本错误的事吗?

更新:旁注:不是立即尝试GetObject,而是可以尝试检查密钥是否实际存在于缓存中,然后才从缓存中检索它.但是,如果我没有弄错的话,除了调用GetObject并捕获异常之外没有其他方法可以进行检查,就像上面的示例一样.对于一个人只想知道项目是否存在的情况,这似乎并不理想.也许在Akavache中使用"存在()"方法会很好吗?或许我错过了什么?

Update2:更改示例以在构造函数中不使用async方法.只是为了证明这不是问题.

Update3:从构造函数中删除调用.当我从代码中的任何地方调用BlockingGetExternalUser时,await仍会挂起.

小智 6

你肯定有一个死锁.引用同步等待异步操作,为什么Wait()在这里冻结程序:

异步方法中的await试图回到UI线程.

由于UI线程忙于等待整个任务完成,因此您有一个>死锁.

请注意,您的电话.Result意味着Task.Wait()某处.

有两种解决方案:要么完全避免使用async方法,要么将代码包装成Task.Run如下所示:

public object BlockingGetExternalUser()
{
    return Task.Run<object>(() => GetExternalUser().Result);
}
Run Code Online (Sandbox Code Playgroud)

(我希望它编译我在VS中没有验证:)

根据经验,我倾向于避免async这些天与SQLite结合使用的方法.原因是大多数SQLite包装器库使用Task.Run反模式来为async它们的方法提供包装器,而SQLite没有任何异步的内在符号.请注意,尽管你将它们包装成Task.Run异步并且它只是库设计者的反模式是完全没问题的,但是向用户建议这些方法在实际上不是异步的时候是异步的.你可以在这里阅读更多相关信息:Task.Run作为反模式?