分离异步HttpClient和Ui线程
本文关键字:Ui 线程 HttpClient 异步 分离 | 更新日期: 2023-09-27 17:51:19
我正在尝试从rest服务下载json数据,我所做的一切是一个按钮点击导航到一个新的页面,并在新的页面我使用异步方法下载数据
但是UI仍然卡住了…UI卡在第一页,直到下载完成。我试过在PageLoaded事件上使用异步。在页面其他元素上的许多其他加载事件中……我怎么把它们分开呢?
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
//download helper
IWebService _downloadClient = new DownloadClient();
var _JsonString = _downloadClient.GetDataAsync(uri);
//Json to Object Converter
IJsonDeserializer _deserializer = new JsonToObject();
ApodProp = _deserializer.DesrializeTo<RootObject>(_JsonString);
apobinding(); //sets some textblocks to the data downloaded
}
整个页面直到下载完成才出现,我没有使用任何await,因为下载客户端的内部方法使用async和await关键字。
下载客户端编辑:
public Task<string> GetDataAsync(string uri)
{
//throw new NotImplementedException();
try
{
using (HttpClient Client = new HttpClient())
{
Task<HttpResponseMessage> _result = Client.GetAsync(uri);
HttpResponseMessage responseData = _result.Result;
return await responseData.Content.ReadAsStringAsync();
}
}
catch (HttpRequestException)
{
MessageDialog md = new MessageDialog("Http exception");
await md.ShowAsync();
}
return null;
}
更新:直到下载完成,我的UI才会显示。
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
await MyTask();
}
myTask:
private async Task MyTask()
{
IApiService _apiProvider = new RestClient.ApiService.NasaAPOD();
var formattableString = _apiProvider.GetFormattableApiCallString("api_key;concept_tags");
IParameterFiller filler = new ParameterFiller();
var uri = filler.FillParameters(formattableString, "I3pA7RdSKvrER6hm6f51BhWzCmoJM6Alq6BjbbEu;true");
IWebService _downloadClient = new DownloadClient();
var _JsonString = await _downloadClient.GetDataAsync(uri);
IJsonDeserializer _deserializer = new JsonToObject();
ApodProp = _deserializer.DesrializeTo<RootObject>(_JsonString);
apobinding();
}
终于搞定了
await Task.Run(()=> { MyTask(); } );
apobinding();
这就是你所需要的…
现在到概念部分…在windows中,有一条规则要求必须从线程访问控件任何包含UI控件的代码都必须在同一个线程上运行,除非你明确地指定它…
在第一种情况下,ui线程(即绑定)与下载代码一起,因此整个ui线程被冻结。
为了得到响应,我不得不把下载放在一个单独的进程。
然后我尝试将ui放在MyTask和task.run中。这两种方式都导致了类似的o/p…是的,正如你所猜测的,根据windows线程规则,如果ui控件从任何其他线程访问,而不是创建它,将导致崩溃崩溃
我有一个真正的艰难的时间响应…但别忘了,如果你的应用程序没有响应,不管是VS、Windows、Mac、Linux还是其他伟大的软件,用户都会卸载的。所以让UI反应灵敏,成为最好的(讽刺)…还有很多事情要做
在评论中你说_downloadClient.GetDataAsync
不是异步的,接口方法也不是。两个选择:
- 使接口方法返回
Task
。 - 将同步下载放到线程池:
await Task.Run(() => _downloadClient.GetDataAsync(uri));
上。这是一个快速解决方案。如果有几个下载同时运行,那么这不是一个性能内存问题,是一个有效的修复。