2016-08-16 45 views
1

我正在通過Xamarin/MonoTouch(所以使用C#而不是Java)構建一個Android應用程序,並希望在應用程序與服務器通信時顯示ProgressBar。我一直在嘗試使用async來做到這一點,但我對線程的工作方式並沒有很好的理解,而且我在過去幾個小時裏遇到了同樣的問題 - ProgressBar在我的方法調用之後顯示,而不是之前。我的代碼在OnCreate()方法中,我也將其重寫爲異步。這是它:用Xamarin顯示Android ProgressBar

 loginButton.Click += async (sender, e) => 
     { 
      progbar.Visibility = ViewStates.Visible; 

      var userFetcher = new UserFetcher(); 
      var json = await userFetcher.FetchUserDetailsAsync(/*parameters*/); 
      //the above method is async and returns a Task<JsonValue> 
      ParseUserDetails(json); //another method I created 

      progbar.Visibility = ViewStates.Invisible; 
      //do some stuff using the parsed data 
     }; 

我遇到的問題是,FetchUserDetailsAsync似乎阻止我的線程。我一直在通過關閉服務器來測試它,以便它需要很長的響應時間(但即使當我測試像Thread.Sleep(5000)這樣的東西時,我也有同樣的問題)。在調用該方法之後,它會一個接一個地運行progbar.Visibility = ViewStates.Visible;progbar.Visibility = ViewStates.Invisible; - 我知道這是因爲當我註釋掉Invisible部分時,ProgressBar在我的方法從服務器獲得「響應」後出現。編譯器也一直給我發送消息,如「跳過67幀!應用程序可能在其主線程上做了太多工作。」

就像我之前說過的,我對線程並不是很有經驗,所以很可能我只是天真地做錯了什麼。有沒有人有解決這個問題?

編輯:這裏爲FetchUserDetailsAsync源代碼:

public async Task<JsonValue> FetchUserDetailsAsync(string url, string username, string password) 
    { 
     HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url)); 
     request.ContentType = "application/json"; 
     request.Method = "GET"; 

     string myBasicHeader = AuthenticationHelper.MakeHeader(username, password); 

     request.Headers.Add("Authorization", "Basic " + myBasicHeader); 

     try 
     { 
      using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
      { 
       using (Stream stream = response.GetResponseStream()) 
       { 
        JsonValue jsonDoc = await Task.Run(() => JsonObject.Load(stream)); 
        return jsonDoc; 
       } 
      } 
     } 
     catch (WebException e) 
     { 
      Console.WriteLine(e.ToString()); 
      if (e.Status == WebExceptionStatus.ProtocolError) 
      { 
       var response = e.Response as HttpWebResponse; 
       if (response != null) 
       { 
        Console.WriteLine("HTTP Status Code: " + (int)response.StatusCode); 
       } 
       else 
       { 
        Console.WriteLine("No http status code available"); 
       } 
      } 
      return null; 
     } 
    } 

回答

1

它看起來像要麼FetchUserDetailsAsync或ParseUserDetails阻止UI線程。因爲Task.Sleep(5000)正在同步運行。嘗試等待Task.Delay(5000);在FetchUserDetailsAsync的行中查看進度條是否顯示。如果是這樣,那麼你可能需要進入FetchUserDetailsAsync實現,以確保它實現異步

+0

非常有趣。當我嘗試Task.Delay()時,事情就像我想的那樣工作。我正在調查FetchUserDetailsAsync以查看可能存在的問題 – Captain

+0

我花了一些時間查看FetchUserDetailsAsync(),我無法真正瞭解可能是什麼問題。它使用異步調用來'等待Task.Run()'。代碼的另一半隻是捕獲異常,如果情況如此,則返回null。使用'await Task.Yield()'實際上給ProgressBar時間顯示,但它不動畫 - 就像FetchUserDetailsAsync()在某種程度上仍然同步運行一樣。我將在OP中發佈這些數據的源代碼 – Captain

1

我想出了這個問題。我在我的FetchUserDetailsAsync方法中調用GetResponse()而不是GetResponseAsync()