2016-08-21 55 views
1

我試圖測試ModernHttpClient的速度,當我遇到以下情況時:標籤未更新,並且按鈕在下面的代碼中一次都未被禁用(在Nexus 5x上測試),而是等待點擊到一直處理到最後!那是什麼,我的一個錯誤,一個錯誤或一個奇怪的「優化」功能?爲什麼標籤文本不能即刻更改?

的Page1.xaml:

<?xml version="1.0" encoding="utf-8" ?> 
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
      x:Class="ModernClientBenchmark.Page1"> 
    <StackLayout> 
    <Button Text="Run the test!" Clicked="OnTestClicked" x:Name="btn"></Button> 
    <Label Text="here we are" x:Name="labl"/> 
    </StackLayout> 
</ContentPage> 

Page1.xaml.cs:

public partial class Page1 : ContentPage 
{ 
    private const int TESTQ = 3; 

    public Page1() 
    { 
     InitializeComponent(); 
    } 

    private async void OnTestClicked(object sender, EventArgs e) 
    { 
     btn.IsEnabled = false; 
     var l1 = new double[TESTQ]; 
     var l2 = new double[TESTQ]; 
     for (int i = 0; i < TESTQ; i++) 
     { 
      Device.BeginInvokeOnMainThread(() => labl.Text = "Step " + i); 
      l2[i] = (await ManagedNetworkSpeedAsync(true)).Milliseconds; 
      //l1[i] = (await NativeNetworkSpeedAsync(true)).Milliseconds; 
     } 

     //var avg1 = l1.Sum()/TESTQ; 
     //var avg2 = l2.Sum()/TESTQ; 

     var a = 234; 

    } 

    public static async Task<TimeSpan> NativeNetworkSpeedAsync(bool secure) 
    { 
     using (var client = new HttpClient(new NativeMessageHandler())) 
     { 
      return await RunTestAsync(secure, client); 
     } 
    } 

    public static async Task<TimeSpan> ManagedNetworkSpeedAsync(bool secure) 
    { 
     using (var client = new HttpClient()) 
     { 
      return await RunTestAsync(secure, client); 
     } 
    } 

    public static async Task<TimeSpan> RunTestAsync(bool secure, HttpClient client) 
    { 
     try 
     { 

      var start = DateTime.Now; 
      for (var i = 0; i <= 1; i++) 
      { 
       var result = client.GetStreamAsync(secure ? "https://xamarin.com" : "http://httpbin.org/ip").Result; 
       result.Dispose(); 
      } 
      return DateTime.Now - start; 
     } 
     catch (Exception ex) 
     { 
      var a = 234; 
     } 
     return new TimeSpan(); 
    } 
} 

回答

1

你已經在UIThread上並且阻止了你自己,你需要將你的工作放到線程池中並從那裏更新UI,await Task.Run塊將完成這項工作。

這會給你,你所期望的結果:

private async void OnTestClicked(object sender, EventArgs e) 
{ 
    btn.IsEnabled = false; 
    var l2 = new double[TESTQ]; 
    await Task.Run(async() => { 
     for (int i = 0; i < TESTQ; i++) 
     { 
      Device.BeginInvokeOnMainThread(() => labl.Text = "Step " + i); 
      l2[i] = (await ManagedNetworkSpeedAsync(true)).Milliseconds; 
     } 
    }); 
    foreach (var x in l2) 
    { 
     System.Diagnostics.Debug.WriteLine(x); 
    } 
    btn.IsEnabled = true; 
} 
1

既然你開始一個異步操作和它正在與UI線程同步,在UI線程有時間執行整個更改之前,整個標籤不會改變。

這是現代應用程序的常規行爲,您不希望爲長時間運行的操作(即通過HTTP請求外部資源等異步操作)阻止UI。

順便說一句,您可以在開始異步操作之前禁用按鈕,並在完成後再次啓用它。

+0

我使用'await'所以代碼應該在不同的線程中運行。對? – nicks

+0

@NikaGamkrelidze在你的情況,是的,BTW async/await本身並不意味着「其他線程」。 –

+0

那麼,你在說什麼?如果代碼在不同的線程中運行,爲什麼UI線程被阻塞? – nicks