我想在Windows Phone 8应用程序中使用可移植类库。 PCL仅包含异步方法,这很好。但我想调用Application_Launching
事件处理程序中的一种方法,结果 等待,以便我可以立即使用它主页被加载。
这些类似的问题对我没有帮助:
为了便于复制,以下代码类似但更简单:
PCL :
public class TestAsyncClass
{
public async Task<string> SendRequestAsync()
{
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync("http://www.google.com").ConfigureAwait(false);
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
}
正如您所看到的,正在等待的方法调用有ConfigureAwait(false)
,因此应该没有死锁,因为该方法想要返回一些捕获的上下文。至少这是我理解Stephen Cleary关于该主题的博客文章的方式:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
App.xaml.cs :
private async void Application_Launching(object sender, LaunchingEventArgs e)
{
TestAsyncLib.TestAsyncClass tac = new TestAsyncLib.TestAsyncClass();
//string result = await tac.SendRequestAsync(); // GlobalData.MyInitString is still empty in MainPage.xaml.cs OnNavigatedTo event handler
string result = tac.SendRequestAsync().Result; // Gets stuck
GlobalData.MyInitString = result;
}
正如在注释中所写,当异步调用该方法时,GlobalData.MyInitString在MainPage.xaml.cs OnNavigatedTo事件处理程序中尝试访问它时仍为空,因为UI线程立即获得焦点并启动主页面在库方法能够返回任何结果之前。并且同步调用该方法会导致库方法卡住。
这是 MainPage.xaml.cs :
protected override void OnNavigatedTo(NavigationEventArgs e)
{
System.Diagnostics.Debug.WriteLine(GlobalData.MyInitString);
}
为了完整性, GlobalData.cs :
public static class GlobalData
{
public static string MyInitString { get; set; }
}
我很感谢你的帮助!
答案 0 :(得分:2)
您无法在OnNavigatedTo
中使用获取的值,因为OnNavigatedTo
与您在Application_Launching
中启动的异步方法并行调用。
这是因为Application_Launching具有返回类型void
并且无法等待void方法 - 因为它们没有任何有意义的返回; - )
这意味着应用程序已启动,您可以触发某些操作。
然后,应用确定要加载哪个页面并触发您的OnNavigatedTo
方法。
现在你可以在那里触发你的异步方法,或者保存一个你可以访问的全局变量来保存结果的任务状态,并检查这个。
让我举一个关于那个任务的例子。
考虑一下Application_Launched
方法:
MyStaticClass.Result = tac.SendRequestAsync();
MyStaticClass中的数据定义是:
public static Task<string> Result;
现在在您的电话页面OnNavigatedTo:
if (MyStaticClass.Result != null)
{
string myResult = await MyStaticClass.Result;
}
您也可以使用单例来代替静态类或属性。
但请记住,OnNavigatedTo
方法也是一个void方法,即使您的数据加载可能尚未完成,您的viewModel也已经从底层UI获取读取请求。
答案 1 :(得分:0)
我现在正在回答我自己的问题,但感谢eX0du5指出了正确的方向。
eX0du5指出无法等待void方法,因为它们没有返回任务。搜索“Application_Launching returns Task”让我看到一篇很棒的msdn博客文章,详细解释了所有内容:
事情是:事件处理程序无法返回任务,并且在应用程序生命周期事件处理程序中调用异步方法的建议是:“不要。”
此外,在博客文章的最后一段中,作者说在异步方法上使用.Wait()
可能有效,但是当UI线程引起调度程序的注意时,它可能会死锁。
因此解释了我对两种不同方法的两个问题。现在做什么? eX0du5的建议(将任务而不是数据保存到GlobalData
静态类)是一种解决方法。如果需要从不同的页面访问应用程序启动时请求的数据,这似乎是一个很好的解决方案,如果仅在启动应用程序后未加载的页面上需要数据,它甚至似乎就像预取数据一个非常好的解决方案。我刚刚检查过任务是在创建时执行的,而不仅仅是等待.Result
或.Wait()
与this code一起使用时。
出于我的目的,因为我只使用GlobalData
来使用MainPage.xaml.cs中的数据,这些数据在启动应用程序时被加载,所以似乎不那么混乱,更简洁,不使用Application_Launching
事件处理程序alltogether,而是在OnNavigatedTo
事件处理程序中执行所有操作。这就是Noseratio对我的问题的评论派上用场的问题,以及关于SO的问题:When should I load data in a Windows Phone 8 application?。