分离异步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反应灵敏,成为最好的(讽刺)…还有很多事情要做

分离异步HttpClient和Ui线程

在评论中你说_downloadClient.GetDataAsync不是异步的,接口方法也不是。两个选择:

  1. 使接口方法返回Task
  2. 将同步下载放到线程池:await Task.Run(() => _downloadClient.GetDataAsync(uri));上。这是一个快速解决方案。如果有几个下载同时运行,那么这不是一个性能内存问题,是一个有效的修复。