2016-08-16 46 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()