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作为反模式?